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.

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{}{}
share|improve this question
add comment

3 Answers

up vote 10 down vote accepted

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}%
 \advance\@tempdimc\@tempdima
 \vrule\@width\@tempdimb\@height\@tempdimc\@depth-\@tempdima}}


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

Another test \Rule{100pt}{1pt}
\end{document}
share|improve this answer
1  
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
add comment

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

share|improve this answer
add comment
\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}
share|improve this answer
add comment

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.