You are missing two very important \expandafter
s.
The normally used, "correct" code is:
\def\ifeq#1#2{%
\ifx#1#2\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
The difference to a macro which uses #3
and #4
is that the if-statement is fully processed before the first or second of the next two arguments is processed. This allows that code to e.g. look ahead using \@ifnextchar
. Otherwise the \else
or \fi
would still be after the #3
or #4
, respectively, which would break such macros. Such techniques to close the if-statement first are also important for recursive macro to not accumulate a lot of cascaded if-statements.
The macros are defined \long
simply to allow for the most flexible use.
The \@firstofone
macro seems to be a no-op, but actually removes the braces around the argument. It is often used in an if-statement where \@gobble
is used in the other clause (both again using \expandafter
).
\def\foo#1#2{%
\ifx#1#2%
\expandafter\@firstofone
\else
\expandafter\@gobble
\fi
}
\foo{\bar}{\baz}{Argument code}
Two objections come to mind:
- If you don't know you will be entering math mode, then you may write something "semantically" correct that breaks.
For example:
\documentclass{article}
\newcommand\mathmacro[1][A]{\ensuremath{{#1}_1}}
\begin{document}
\mathmacro[$x^2$] % The dollar signs *leave* math mode
\end{document}
What's going on here is that \mathmacro[$x^2$]
expands to
\ensuremath{{$x^2$}_1}
which expands to (effectively)
\ifmmode
{$x^2$}_1
\else
${$x^2$}_1$
\fi
and you can see that if you write it outside of math mode, the second branch is taken, so the first dollar sign brings you into math mode and the one at the front of $x^2$
takes you out of it, with the reverse operation happening afterwards. This gives an error.
Of course, you aren't supposed to do that, since \mathmacro
is actually a "math macro usable in text mode", so you should think of the thing between the brackets of its argument as being in math mode. Alas, this confuses both the author and the text editor's syntax highlighting, since it is a nonstandard assumption.
Edit: I would define this macro as:
\newcommand\mathmacro[1][A]{{#1}_1}
and use it as:
$x^2$ sub one: $\mathmacro[x^2]$.
This way, the parts that are math are clearly math.
- In the unlikely event that you or some package sets
\everymath
, you will be very surprised when your apparently text-mode macros start to look different.
On the subject of semantics, though, the issue is clear: \ensuremath
breaks the separation between math and text, which are two very different things. TeX even has the distinction built in: different fonts, different spacing rules, different parsing rules. You can probably construct a lot more counterexamples by exploiting these.
What I mean by this is that in the following situation:
\documentclass{article}
\newcommand\mathmacro[1][A]{\ensuremath{{#1}_1}}
\begin{document}
A sub one: \mathmacro
\bfseries A sub one: \mathmacro
\end{document}
you may be surprised that the bold text does not extend to the contents of the apparently text-mode \mathmacro
.
What I'm saying is not so much that \ensuremath
actually breaks anything as that it violates your expectations to the point that it makes things harder rather than easier.
Best Answer
New answer
A LaTeX kernel later than June 2020 will provide the better
but also
\RenewCommandCopy
and\DeclareCommandCopy
. The first one does the same work as\LetLtxMacro
as described in the “original answer”, but can also be employed with commands defined via\NewDocumentCommand
(or siblings).Differently from
\LetLtxMacro
, it will raise an error if the alias we want is already defined. In this case one can use\RenewCommandCopy
(that raises an error if the alias is not defined) or\DeclareCommandCopy
(no check is performed). Be careful when using these two forms.Do prefer
\NewCommandCopy
over\let
, unless you precisely know that\let
is OK.Original answer
There are two main cases when
\LetLtxMacro
should be used (and it doesn't harm if used in other cases).Case 1
The command to get a copy of has been defined with
\DeclareRobustCommand
, like(with any number of arguments, even zero). There are other commands defined in different ways, but at the end come up as being in this same case.
What happens here is that LaTeX defines two commands, in a way similar to this
where by
•
I mean a space in the name of the second command. How this trick is achieved is unimportant. We can realize if a command is of this kind by askingtexdef
: with the command linewe get
This shows precisely what's happening:
texdef
prints first the meaning of\texttt
, which is\protect\texttt•
(the space here is invisibile), but then know about the nature of this command and so prints also the meaning of\texttt•
and this is shown by the space before the colon.What would be the problem in doing
for changing the working of
\foo
? Let's see what happens (I'll continue to use•
for denoting the space in the name of a macro).which seems pretty good: the renewed macro does what we want. But wait! We use
\DeclareRobustCommand
to be sure that\foo
in moving arguments is treated correctly. So let's see what happens when\foo{BAR}
is used in a moving argument, such as a section title; the annotation in the.toc
file will containwhich in the end will result in printing
!!-BAR-!!
, which is not what we want. Why? Because the writing process expands unprotected macros. So LaTeX doesSince
\foo•
was preceded by\protect
, the last line is what's written. But when the.toc
file is read in, TeX only sees a space after\foo
, because it inputs a text file, so it will dutily expand\foo
.If one uses
LaTeX will essentially do
so that the problem above will not appear any more.
Case 2
If the command we want to save the meaning of has been defined with
\newcommand
to have an optional argument, then there are risks like in the previous case; they are explained in this answer. The situation is of the formand, for instance,
\smash
(as redefined byamsmath
) falls in this case. Withwe'd get
and this is a clear sign that
\LetLtxMacro
should be used.Other cases
If the command to save has been defined with
\newrobustcmd
from theetoolbox
package, then\LetLtxMacro
should be used in order to safely copy its meaning.Warning
Don't try
\LetLtxMacro
with commands defined by\NewDocumentCommand
(or similar commands) fromxparse
. Theletltxmacro
package doesn't support them.