10

I would like to define a macro that takes two arguments, one of which is optional. If it is not given, then it should take the other one as default value.

Unfortunately,

\newcommand{\mycommand}[2][#1]{ ... }

does not work, neither does

\newcommand{\mycommand}[2][#2]{ ... }

Does anybody know how to do this?

2
  • \newcommand{\mycommand}[2][default]{...}?
    – user121799
    Commented Mar 8, 2019 at 6:40
  • The problem is that putting #1 or #2 as default value does not work. Using an arbitrary fixed default value works just fine, but is not what I want. Commented Mar 8, 2019 at 6:41

3 Answers 3

11

Good news: you can do it very easily with xparse:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\foo}{O{#2}m}{%
  Optional=``#1'', mandatory=``#2''\par
}
\NewDocumentCommand{\oof}{mO{#1}}{%
  Mandatory=``#1'', optional=``#2''\par
}

\begin{document}

\foo{x}

\foo[y]{x}

\oof{x}

\oof{x}[y]

\end{document}

The argument specifier O{...} takes as argument what to substitute as default when the argument itself doesn't appear at call time. This can well be a parameter token referring to another argument.

enter image description here

9

You can use xparse to easily condition on whether or not an optional argument was present or not, and supply the appropriate combination to another (auxiliary) function. Here's an example:

enter image description here

\documentclass{article}

\usepackage{xparse}

\newcommand{\printthis}[2]{%
  Optional: #1; Mandatory: #2%
}

\NewDocumentCommand{\mycommand}{o m}{%
  \IfValueTF{#1}
    {\printthis{#1}{#2}}% \mycommand[..]{...}
    {\printthis{#2}{#2}}% \mycommand{...}
}

\begin{document}

\mycommand{first}

\mycommand[first]{second}

\end{document}

A slightly different version of this stems from the use of \caption, where you can supply an optional argument for the LoT/LoF, but if you don't, the mandatory arguments is sent instead (similarly for sectional units with optional arguments destined for the ToC). This uses the kernel's \@dblarg:

\documentclass{article}

\newcommand{\printthis}[2][]{%
  Optional: #1; Mandatory: #2%
}

\makeatletter
\newcommand{\mycommand}{%
  \@dblarg\printthis
}
\makeatother

\begin{document}

\mycommand{first}

\mycommand[first]{second}

\end{document}
1
  • Great, thank you very much! Commented Mar 8, 2019 at 6:53
2

This is an attempt to add protection as with other macros that process optional arguments:

%%\errorcontextlines=1000
\documentclass[a4paper]{article}

\makeatletter
\newcommand\makefirstmandatorytheoptional[1]{%
  \expandafter\innermakefirstmandatorytheoptional
  \expandafter{\csname\string#1\endcsname}{#1}%
}%
\newcommand\innermakefirstmandatorytheoptional[2]{%
  \def#2{%
    \ifx\protect\@typeset@protect
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
    {\kernel@ifnextchar[{#1}{\@dblarg{#1}}}%
    {\protect#2}%
  }%
}%
\newcommand\mycommand[2][dummyoptional]{%
  This is taken for the optional argument: #1.\\
  This is taken for the mandatory argument: #2.
}%
\makefirstmandatorytheoptional{\mycommand}%
\makeatother

\parindent=0ex
\parskip=\medskipamount

\begin{document}

No optional argument given---\verb|\mycommand{A}|:

\mycommand{A}

Optional argument "B" given---\verb|\mycommand[B]{A}|:

\mycommand[B]{A}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .