Using the compulsory argument for the optional argument?
The classical approach for this is to use \@dblarg
:
\documentclass{article}
\makeatletter
\newcommand{\foo}{\@dblarg\ah@foo}
\def\ah@foo[#1]#2{#1 foo(#2)}
\makeatother
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
With xparse
it's easier:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\foo}{om}{%
\IfNoValueTF{#1}{#2}{#1} foo(#2)%
}
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
Wherever you need the optional argument, you type \IfNoValueTF{#1}{#2}{#1}
.
There's a much slicker way if you have xparse
released 2017/02/10 (or later): an optional argument O
can take as default any of the mandatory argument:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\foo}{ O{#2} m }{%
#1 foo(#2)%
}
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
So we're telling \foo
that, if the optional argument is missing (first call), the mandatory argument #2
should be used also as value for #1
. In the second call, the optional argument is given, so it's substituted for #1
.
This is pretty easy with \NewDocumentCommand
from xparse
, checking whether the optional argument (o) was given or not with \IfValueTF{#1}{}{}
.
Not so easy with \newcommand
, however. Define a command without arguments, say \foobar
and check with \@ifnextchar[{}{}
whether the next character is a [
and branch into a command that uses []{}
arguments and another one, that does only use the mandatory argument, i.e. {}
. This technique is called 'moving arguments'.
This way does not need other extra packages and applies LaTeX core features. The only 'tricky' point is to use the \makeatletter...\makeatother
pair.
\@ifnextchar[
looks for [
and if this is found, the character is basically 'shifted' back such that \foobar@opt
can find it again as start of a command with optional argument (Actually, [
is stored to a temporary macro and expanded for the true
branch if [
has been found)
\documentclass{article}
\usepackage{xparse}
\makeatletter
\newcommand{\foobar}{%
\@ifnextchar[{\foobar@opt}{\foobar@noopt}
}{}
\newcommand{\foobar@opt}[2][]{%
#1 foo(#2)%
}
\newcommand{\foobar@noopt}[1]{%
#1 foo(#1)%
}
\makeatother
\NewDocumentCommand{\foo}{om}{%
\IfValueTF{#1}{%
#1 foo(#2)%
}{%
#2 foo(#2)%
}%
}
\begin{document}
\foo[hello]{hi}
\foo{hi}
\foobar[hello]{hi}
\foobar{hi}
\end{document}
You can supply a default value for the optional argument, and use this to condition on whether or not it was supplied in the first place.
\documentclass{article}
\newcommand{\foo}[2][\relax]{%
\ifx\relax#1\relax #2\else #1\fi
~foo(#2)%
}
\begin{document}
\foo[hello]{hi}
\foo[]{hi}
\foo{hi}
\end{document}
Above I specified that the optional argument will default to \relax
if it is not supplied, and then check \ifx\relax#1\relax
to either place #2
or #1
. \ifx
compares the following two tokens for equivalence.