# Defining a macro in LaTeX with an optional parameter in round brackets

Is it possible to build a macro with an optional parameter enclosed in round brackets () rather than square brackets, where one can say for example:

\mymacro(){}{}


or

\mymacro{}{}


A more traditional solution!

To build a command with any optional parameter, as you find in many of LaTeX's commands, you will need two things:

(a) a macro with delimited parameters

(b) a way to grab the first non-space token that follows the command

The first part is fairly easy using delimited argument macros, for example we can say

 \def\test(#1)#2#3{#1, #2, #3}


We can then call this macro as:

 \test(a){b}{c}


resulting in a,b,c

To define the () as an optional parameter, we effectively need to define the macro as a conditional a sort of a "yes-no" switch. If TeX finds the "(" bracket the "yes-code" will be called and if it finds only the normal arguments the "no-code" will be executed.

For this we can use the \@ifnextchar macro from the LaTeX kernel. You can say \@ifnextchar{char}{yes-code}{no-code} to test for (. The result then will depend on the token that follows. If this token is the same as the first argument, then the "yes-code" is executed, otherwise the "no-code" is executed. The first argument should be a single token (for instance a character). Spaces are ignored.

As for example we can redefine the LaTeX code for rule to accept an optional parameter in round brackets, rather than the traditional square brackets.

\def\Rule{\@ifnextchar(\@Rule%
{\@Rule(\z@)}}


and the full example would look like:

\documentclass{article}
\begin{document}
\def\Rule{\@ifnextchar(\@Rule%
{\@Rule(\z@)}}
\def\@Rule(#1)#2#3{%
\leavevmode
\hbox{%
\setlength\@tempdima{#1}%
\setlength\@tempdimb{#2}%
\setlength\@tempdimc{#3}%
\vrule\@width\@tempdimb\@height\@tempdimc\@depth-\@tempdima}}

A test \Rule(6.5pt){100pt}{1pt}

Another test \Rule{100pt}{1pt}
\end{document}

• Very nice explanation! Of course, this has the same feature as LaTeX's own optional parameters: an option of the form (...(...)...) will only grab to the first parenthesis (except if inner ones are hidden within braces). – Bruno Le Floch Mar 7 '11 at 21:09

A simple xparse-based solution:

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand\mymacro{d()mm}{%
\IfNoValueTF{#1}
{}% Case where #1 is not given
{}% Case where #1 is given
}


or if you want an empty #1 when it is not present:

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand\mymacro{D(){}mm}{%
% Code here
}


(This works as d/D indicate an optional argument which is delimited.)

\documentclass{article}
\makeatletter
\def\mymacro{\@ifnextchar(\mymacro@i\mymacro@ii}
\def\mymacro@i(#1)#2#3{%
#1:#2:#3}% the definition
\def\mymacro@ii#1#2{%
#1:#2}% the definition
\makeatother
\begin{document}

\mymacro(foo){bar}{baz} -- \mymacro{BAR}{BAZ}

\end{document}