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.
You have to make an additional comparison on those arguments specified as []
, which technically differ from \NoValue
. And, you can't just leave them out, since subsequent optional arguments would then be used out-of-sequence. You can use the ifmtarg
package:
\documentclass{minimal}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\usepackage{ifmtarg}% http://ctan.org/pkg/ifmtarg
\makeatletter
\DeclareDocumentCommand{\mycommand}{ O{mydefault} m o o o }{%
p:#2%
\IfNoValueTF{#3}%
{}%
{\@ifmtarg{#3}{}{ p:#3}}%
\IfNoValueTF{#4}%
{}%
{\@ifmtarg{#4}{}{ p:#4}}%
\IfNoValueTF{#5}%
{}%
{\@ifmtarg{#5}{}{ p:#5}}
p:#1
}
\makeatother
\begin{document}
\mycommand[one]{two} \par % p:two p:one
\mycommand[one]{two}[three] \par % p:two p:three p:one
\mycommand[one]{two}[three][four] \par % p:two p:three p:four p:one
\mycommand[one]{two}[three][four][five] \par % p:two p:three p:four p:five p:one
\mycommand[one]{two}[three][][five] \par % p:two p:three p:five p:one
\mycommand[one]{two}[][][five] % p:two p:five p:one
\end{document}
Best Answer
You can't "overload" macros in TeX like functions in other programming languages.
You can either define the macro to use a normal optional argument for one of the two parameters or define a special macro which looks ahead if a opening brace follows. The
xparse
package can help you defining one:Here the
m
in the definition stand for mandatory argument and theg
for optional argument delimited by a TeX group, i.e.{}
.