# Different command definitions with and without optional argument

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?

-
–  Peter Grill Nov 3 '12 at 16:05

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{http://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.

-
This solution is very nice and clean, thanks! –  Juan A. Navarro Jul 27 '10 at 8:27
@Konrad: absolutely! Never use raw TeX unless you know what you are doing! But surrounding the whole thing in an \@ifundefined would satisfy your requirement, I deem. –  Loop Space Jul 27 '10 at 8:35
Yup, I know the difference on when and when not to use each. I'm a bit of a TeX-hacker myself ;-) Also thanks for your LaTeX-friendlier solutions! –  Juan A. Navarro Jul 27 '10 at 8:37
Perhaps worth saying that - for the archive - I wouldn't feel happy if this were the only solution posted, but as Konrad had already given a LaTeX solution, I felt happy posting a TeX one. –  Loop Space Jul 27 '10 at 10:26

The LaTeX3 xparse package is designed to aid the construction of macros that take complex optional arguments. In this case, you'd write

\usepackage{xparse}
....
\DeclareDocumentCommand \foo { o m } {%
\IfNoValueTF {#1} {%
\something {#2}%
}{%
\someotherthing {#1} {#2}%
}%
}


Internally, this does the same thing as Andrew's answer, but the coding is a little more straightforward/readable and it is also more easily extended. Want another optional argument? Just add another o in the { o m } argument. (o is ‘optional argument’ and m is ‘mandatory argument’; see the xparse documentation for more.)

-
Does \IfNoValue check if the second argument was supplied or does it check if the first argument was empty. That is does it distinguish between \foo[something] and \foo[][something] and what if I want the opposite behaviour? –  Aditya Sep 9 '10 at 16:38
It checks if the first argument was not supplied. It is also possible to specify a default with O{default} which I think might be what you're thinking of. There isn't an \IfEmpty conditional in xparse but there is an equivalent in expl3 or ifmtarg. –  Will Robertson Sep 9 '10 at 22:50
Better use \IfNoValueTF {#1} {%. If the optional argument takes more then one digit, this will be important. –  LaRiFaRi Mar 27 at 13:56

I want to thank for all of the other answers received. But lately I've turned into a huge fan of the etoolbox package, which provides a great abstraction to do exactly what I wanted at the LaTeX level (with no low level TeX trickery):

\usepackage{etoolbox}

\newcommand\mycmd[2][]{%
\ifstrempty{#1}{%
% something with #2
}{%
% some other thing with #1 and #2
}%
}

-

I'd prefer Will Robertson's solution, that's more manageable. For a "pure" LaTeX solution:

\makeatletter
\def\ifemptyarg#1{%
\if\relax\detokenize{#1}\relax % H. Oberdiek
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
\makeatother

\newcommand{\mycmd}[1][]{%
\ifemptyarg{#1}
{<code for empty argument>}
{<code for non empty argument>}%
}

-

I usually just use the ifthen package to solve this, by testing whether the optional argument is empty.

\newcommand\mycmd@noargs{foo}
\newcommand\mycmd@withargs[1]{bar #1}
\newcommand\mycmd[1][]{
\ifthenelse{\equal{#1}{}}{
\mycmd@noargs{}}{
\mycmd@withargs{#1}}}


(Notice that since it uses @ as a letter, you need to use \makeatletter before this definition if it’s in your main LaTeX file (instead of a package), and \makeatother after it.)

-
This is not really a solution, I'm afraid: test it with \mycmd[aa] where \ifx returns true because it compares a with a. –  egreg Jun 5 '12 at 11:07
@egreg Whoa. Surprising that nobody has noticed this for two years. –  Konrad Rudolph Jun 5 '12 at 12:23
(Note that egreg and Konrad are discussing a pure-Tex alternative that has now been edited out.) –  dubiousjim Jun 30 '14 at 9:18