[Tex/LaTex] When to use \LetLtxMacro

macros

Frequently I see users redefine macros using (for example)

\let\oldmacro\macro% Store \macro in \oldmacro
\renewcommand{\macro}{%
  % ...redefined \macro
  \oldmacro%
}

and other times they use

\usepackage{letltxmacro}% http://ctan.org/pkg/letltxmacro
\LetLtxMacro{\oldmacro}{\macro}% Store \macro in \oldmacro
\renewcommand{\macro}{%
   % ...redefined \macro
  \oldmacro%
}

Why would one use \LetLtxMacro when \let works just as well? Or, more specifically, when would one use \LetLtxMacro and/or why?

Best Answer

New answer

A LaTeX kernel later than June 2020 will provide the better

\NewCommandCopy

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

\DeclareRobustCommand{\foo}[1]{-#1-}

(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

\def\foo{\protect\foo•}
\newcommand\foo•[1]{-#1-}

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 asking texdef: with the command line

> texdef -t latex texttt

we get

\texttt:
macro:->\protect \texttt  

\texttt :
\long macro:#1->\ifmmode \nfss@text {\ttfamily #1}\else \hmode@bgroup \text@command {#1}\ttfamily \check@icl #1\check@icr \expandafter \egroup \fi 

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

\let\oldfoo\foo
\renewcommand\foo[1]{!\oldfoo{#1}!}

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).

\foo{BAR}
!\oldfoo{BAR}!
!\protect\foo•{BAR}!
!-BAR-!

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 contain

!\foo  {BAR}!

which in the end will result in printing !!-BAR-!!, which is not what we want. Why? Because the writing process expands unprotected macros. So LaTeX does

\foo{BAR}
!\oldfoo{BAR}!
!\protect\foo•{BAR}!
!\foo• {BAR}!

Since \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

\LetLtxMacro{\oldfoo}{\foo}

LaTeX will essentially do

\def\oldfoo{\protect\oldfoo•}
\let\oldfoo•\foo•

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 form

\newcommand{\xyz}[2][!]{#1-#2}

and, for instance, \smash (as redefined by amsmath) falls in this case. With

texdef -t latex -p amsmath smash

we'd get

\smash:
macro:->\@protected@testopt \smash \\smash {tb}

and this is a clear sign that \LetLtxMacro should be used.

Other cases

If the command to save has been defined with \newrobustcmd from the etoolbox 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) from xparse. The letltxmacro package doesn't support them.

Related Question