Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
    
See also: latex optional arguments on StackOverflow. –  Sadeq Dousti Jul 17 '11 at 12:50
    

5 Answers 5

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.)

share|improve this answer
6  
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
1  
@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 at 9:18

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.

share|improve this answer
    
This solution is very nice and clean, thanks! –  Juan A. Navarro Jul 27 '10 at 8:27
2  
@juan: but it uses \def instead of \newcommand which isn’t recommended in LaTeX. To note just one advantage, \newcommand tests whether the command already exists and provides meaningful diagnostics, while \def will just override the command, potentially breaking other code. So, in summary, don’t use \def when \newcommand will do. –  Konrad Rudolph Jul 27 '10 at 8:29
2  
@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.)

share|improve this answer
    
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
3  
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

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>}%
}
share|improve this answer
up vote 20 down vote accepted

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
  }%
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.