[Tex/LaTex] Different command definitions with and without optional argument

macrosoptional arguments

I want to define a command that expands to two completely different things depending on whether I supply, or not, an optional argument. For example,

\mycmd{normal}            ->  something(normal)
\mycmd[optional]{normal}  ->  anotherthing(normal, optional)

How can I do this?

Best Answer

If you read deep in the LaTeX code you can find lots of examples where this is done. Any command that has optional arguments actually does this already: there are actually two different commands and which one is called depends on whether or not it is called with an optional command. The TeX trick is to use \@ifnextchar[. For example,

\def\mycmd{\@ifnextchar[{\@with}{\@without}}
\def\@with[#1]#2{hello #1, have you met #2?}
\def\@without#1{goodbye #1}

What happens there is that the TeX interpreter meets the \mycmd macro and expands it (swallowing following white-space, of course). The first thing it then encounters is a test on the next character (which, incidentally, is non-destructive - the next character is simply observed, not processed). If it is a square bracket, then it puts \@with in the stream and starts again. \@with is defined to take two arguments, the first of which is surrounded by square brackets. It therefore matches the first optional argument and the next thingy in the TeX stream. If the next character wasn't a square bracket then \@without is put into the stream. This takes one (normal) parameter. But since \@with and \@without are two completely separate commands, they can do whatever they like with the input.

(Note: For commands defined with \newcommand which take an optional parameter then sort-of what happens is that the two commands \@with and \@without expand to the same command, but the optional parameter of \@with gets passed to it as the first parameter whereas in \@without the default value is passed. It's not quite like that, but the difference is more in conciseness of programming than anything else.)

Here's a fully compilable example, including the mysterious and mystical duo \makeatletter and \makeatother:

\documentclass{article}
%\url{https://tex.stackexchange.com/a/314/86}

\makeatletter
\def\mycmd{\@ifnextchar[{\@with}{\@without}}
\def\@with[#1]#2{Hello #1, have you met #2?}
\def\@without#1{Goodbye #1.}
\makeatother

\begin{document}
\mycmd[Polyphemus]{Odysseus}
\mycmd{Circe}
\end{document}

Produces:

Hello Polyphemus, have you met Odysseus? Goodbye Circe.

Related Question