2

What's wrong with this code:

\documentclass{article}
\begin{document}
\let\first\section
\renewcommand\section[1]{\first{#1}}
\let\second\section
\renewcommand\section[2][]{\second{#1}} % works till this line
\let\third\section
\renewcommand\section[2][]{\third[#1]{#2}}
\section[foo]{Hello}
\end{document}

It doesn't compile.

yegor256
  • 12,021

1 Answers1

4

You should never use \let for commands with optional arguments.

Let's see what happens in this case, taking into account that

\renewcommand\section[2][]{\second{#1}}

actually defines two commands: one is \section which takes no argument and the other one is \\section (with a backslash in its name).

The job of (the redefined) \section is to check for a following [ and to call \\section with the appropriate two arguments, the first being the default if no [ followed \section.

Now you do \let\third\second and \renewcommand\section[2][]{\third[#1]{#2} will basically redefine \\section in terms of itself, causing an infinite loop.

If you use \NewCommandCopy instead of \let (or \LetLtxMacro with the letltxmacro if you have an older LaTeX), there will be no infinite loop.

egreg
  • 1,121,712
  • How do you even define a command with a name such as \\section? Something like \expandafter\def\csname\\section\endcsname{<something>}? Or must I escape the backslash some other way? (I assume yes, since \\ is a completely different macro.) – Gaussler Sep 06 '21 at 11:21
  • 1
    \expandafter\def\csname \string\section \endcsname ... assuming normal \escapechar – plante Sep 06 '21 at 11:34
  • @plante Makes sense. So a command name can contain a backslash. I wonder: Is it possible to have a command name ending in a backslash? Obviously, \\ is one such, but can it be done with command names having more than one character? – Gaussler Sep 06 '21 at 18:34
  • 1
    @Gaussler You can certainly have a command name ending in a backslash: assuming a standard value for \escapechar, \expandafter\def\csname test\expandafter\gobble\string\\\endcsname{test} will do, with \def\gobble#1{} (in LaTeX there is \@gobble). If you activate \tracingassigns=1, you get {changing \test\=\relax} {into \test\=macro:->test} – egreg Sep 06 '21 at 19:48
  • Why is this \gobble necessary? I don’t understand the logic of this this definition of \test\. – Gaussler Sep 07 '21 at 10:38
  • 1
    @Gaussler \string\\ will produce \\ and we want to remove one backslash. – egreg Sep 07 '21 at 10:39
  • Makes sense. A related question: It seems that \csname\endcsname (the empty command name) is defined and equal to \relax. Why in the world is that the case? – Gaussler Sep 07 '21 at 10:49
  • 1
    @Gaussler Anytime you do \csname...\endcsname the sequence is defined as equivalent to \relax unless it already has a definiition. – egreg Sep 07 '21 at 10:51