0

There are many instances where I need to create my own commands and a lot of the time I also need them to have an optional argument. No problems there.

However, I needed to have one of my commands inside the title of a section and then no .pdf was produced. Here is a simplified code:

\documentclass[12pt]{article}

\makeatletter
\newcommand{\foo}{\@ifnextchar[{bracket}{parenthesis}}
\makeatother

\begin{document}

\section{\foo()}
\foo()
\section{\foo[]}
\foo[]

\end{document}

If \section{\foo()} and \section{\foo[]} are removed, then everything seems to work fine. Also, if you remove them, compile, get your .pdf, then add just one of them to the code, then you still get a .pdf even though you couldn't earlier, and if you add the second one it still complies. Always with a bunch of errors.

If I make it more complicated - let's say I have redefined a preexisting command - then not even the old definition of the command works inside the \section environment:

\documentclass[12pt]{article}

\let\doublevowelhyphen\H
\makeatletter
\renewcommand{\H}{\@ifnextchar[{\@foo}{\@ffoo}}
\def\@foo[#1]#2{#2.#1}
\def\@ffoo#1{#1.}
\makeatother

\begin{document}

\section{\doublevowelhyphen{o}}
\doublevowelhyphen{o}
\section{\H{1}}
\H{1}
\section{\H[1]{2}}
\H[1]{2}

\end{document}

Here I get a similar behaviour as before.

Finally, I seem to get additional errors if I'm using the hyperref package which I also need.

I suspect it has something to do with the @ symbol by I don't really understand what's going on. Can someone, please, explain why this is happening?

  • 2
    The problem is basically what is discussed here. Both your commands \foo and \H are fragile and blow up when being written to the .toc file. You need to make them robust. Also commands with optional arguments hardly work in PDF bookmarks, so you may have to need \texorpdfstring from hyperref. If your command will have a mandatory argument (like in the second example) then you can use xparse and \NewExpandableDocumentCommand. Can you explain the exact use case, please? – Phelype Oleinik Jun 29 at 16:59
  • @PhelypeOleinik They could be expandable given a mandatory argument is there ... – Joseph Wright Jun 29 at 17:04
  • Have you tried prefixing \protect before \H and \foo? – Mico Jun 29 at 17:39
  • @Mico That actually works, but it's gonna be a pain to do that every time my commands (kinda) randomly fail. – Jim Jun 30 at 9:28
  • @PhelypeOleinik Wow, I learnt a lot from the reference you had there. Thanks a lot! – Jim Jun 30 at 9:29
2

The question is a little hard to answer as, despite the question title, the example given has no optional argument. (Note the [] following the command is typeset as text not taken as argument delimiter). However it does use the \@ifnextchar construct which would make it fragile, however you can hide that by declaring it as a robust command:

\documentclass[12pt]{article}

\makeatletter
\DeclareRobustCommand{\foo}{\@ifnextchar[{bracket}{parenthesis}}
\makeatother

\begin{document}

\section{\foo()}
\foo()
\section{\foo[]}
\foo[]

\end{document}

Conversely this command, that has an optional argument defined via \newcommand is defined to be robust, but of course has a different behaviour.

\documentclass[12pt]{article}


\newcommand{\foo}[1][bracket]{parenthesis}


\begin{document}

\section{\foo()}
\foo()
\section{\foo[]}
\foo[]

\end{document}
  • You're right, I didn't really give an example matching the title exactly, but it turns out my problem was the fragility of my commands (with or without an optional argument). \DeclareRobustCommand actually makes things work fine for me. I didn't know that existed. Thanks. – Jim Jun 30 at 9:53
  • Although I marked this as solved, could you possibly make another answer (or extend this one) explaining how \DeclareRobustCommand really works so that I don't misuse it? Or maybe point me to where I could find an explanation? – Jim Jun 30 at 10:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.