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.

LaTeX seems to be having problems handling nested optional arguments. I've included a minimal code example that generates the error:

\documentclass[12pt,oneside]{book}
\begin{document}

\newcommand{\termbad}[2][]{#2#1}
\newcommand{\termgood}[2][]{#2#1}

\newcommand{\up}[1]{#1}
\newcommand{\dd}[1][]{#1}

\termgood{\up{Tart}}{Pop}
\termbad[\up{Tart}]{Pop}    

\termgood{\dd[Tart]}{Pop}
\termbad[{\dd[Tart]}]{Pop}
%\termbad[\dd[Tart]]{Pop}


\end{document}

If you run this code, it works. If you remove the % in the second to last line, it fails with:

Runaway argument?

Tart{Pop} \par \par \end {document}

!File ended while scanning use of \dd.

After further tinkering, I have discovered the problem: LaTeX is reading the ] for the inner optional argument as the end of the outer optional argument and then passing a malformed argument in. So it is passing in \dd[Tart as the optional argument to \termbad instead of \dd[Tart].

This still feels like a bug to me. Nesting braces in arguments works, brackets should as well. The following are workarounds:

  • Enclose the inner optional argument in braces (as in the line before %).

  • Redefine your inner function to require its argument instead of using optional arguments.

  • Redefine your outer function to require its argument instead of using optional arguments.

Any one of the three works around the issue.

(Reposted here; question was originally posted to stackexchange and then closed instead of being migrated.)

share|improve this question
    
As far as I can see, the main problem is that LaTeX doesn't define the notion of nested optional arguments. This is why different implementations have different semantics. –  Marc van Dongen Oct 20 '12 at 11:57
add comment

1 Answer 1

up vote 17 down vote accepted

When TeX reads arguments, then TeX only checks for matching curly braces (characters with catcode 1 and 2). Square brackets are not special in this sense. The first ] that is not hidden inside curly braces is taken as the end of the optional argument. Therefore an additional set of braces is the usual solution:

\foo[{\bar[...]}]{...}

It is only a bug, if this does not work, e.g. if the definition passes optional arguments to other commands:

\def\foo#1#2{\bar[#1]{#2}}

This should be

\def\foo#1#2{\bar[{#1}]{#2}}

Then #1 may contain square brackets, especially ].

share|improve this answer
6  
Worth noting that xparse-defined functions do not suffer from this –  Joseph Wright Oct 20 '12 at 11:41
    
Thanks for the answers. I'm looking at xparse now, since I'm using some complex code to create a highly linked and formatted document. This may solve a few of the problems I've been having. –  JKreft Oct 23 '12 at 12:33
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.