8

When I create macros using \newcommand, I usually provide default variants setting some of the first arguments in a sort of partial application style

\newcommand\five[5]{#1,#2,#3,#4,#5}
\newcommand\letters{\five{a}{b}{c}}
\newcommand\numbers{\five{1}{2}{3}}

so that one could just say \numbers{8}{9} and gets 1,2,3,8,9.

Now I want to do this for a command with an optional argument, setting defaults for the first mandatory parameters. As far as I know \newcommand only takes one optional argument which always has to be the first one. So if I want to predefine some arguments with a new command, I have to move the optional argument further down to have it passed through. The following minimal working example shows how I managed to achieve this.

\documentclass{scrartcl}
\newcommand\five[5][f]{#1,#2,#3,#4,#5}
\newcommand\reordered{}
\newcommand\thirdoptional[2]{\renewcommand\reordered[3][f]{\five[##1]{##2}{##3}{#1}{#2}}\reordered}
\newcommand\letters{\thirdoptional{a}{b}}
\newcommand\numbers{\thirdoptional{1}{2}}

\begin{document}
\begin{itemize}
  \item \numbers[3]{4}{5}
  \item \letters[c]{d}{e}
  \item \thirdoptional{v}{w}[x]{y}{z}
  \item \thirdoptional{6}{7}{8}{9}
\end{itemize}
\end{document}

However, I am not satisfied that the helper \reordered is exported to the outside. On top of that, if the default argument of \five changes, this does not propagate to \thirdoptional. Is there another way to reorder arguments?

I know of packages like pgfkeys and keyval that provide more complex argument handling. But the commands I define have to work inside more complex environments than this example shows, especially some of them are defined globally through a TikZ \foreach, so I want to try to abstain from additional packages.

2

1 Answer 1

7

You can test whether an optional argument is given or not (or just test whether it's empty) and condition on that. xparse provides a straight-forward interface:

enter image description here

\documentclass{article}
\newcommand\five[5][f]{#1,#2,#3,#4,#5}
\newcommand\reordered{}
\newcommand\thirdoptional[2]{\renewcommand\reordered[3][f]{\five[##1]{##2}{##3}{#1}{#2}}\reordered}
\newcommand\letters{\thirdoptional{a}{b}}
\newcommand\numbers{\thirdoptional{1}{2}}

\usepackage{xparse}% http://ctan.org/pkg/xparse
\NewDocumentCommand{\numbersA}{o m m}{%
  \IfNoValueTF{#1}% Condition on whether the optional argument is
    {\five{1}{2}{#2}{#3}}%... empty, or...
    {\five[#1]{1}{2}{#2}{#3}}%... not.
}

\begin{document}
\begin{itemize}
  \item \numbers[3]{4}{5}
  \item \letters[c]{d}{e}
  \item \thirdoptional{v}{w}[x]{y}{z}
  \item \thirdoptional{6}{7}{8}{9}
  \item \numbersA{4}{5}
  \item \numbersA[3]{4}{5}
\end{itemize}
\end{document}

The above MWE defines \numbersA[<opt>]{<stuff>}{<stuff>} that inserts the optional argument <opt> into the correct place where it's needed for \five. A similar definition for \lettersA could be made.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .