89

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?

4
  • See “Closed” (square) root symbol. In particular, see @egreg's comment.
    – A.Ellett
    Dec 23, 2012 at 7:26
  • @A.Ellett The "x mins/hours ago" text at the end of each comment is a link that leads directly to the comment. At the end of each answer there is a light grey list of functions "share edit flag". The "share" is a link to the corresponding answer as well. Dec 23, 2012 at 21:26
  • This is explained clearly in the package documentation. Dec 25, 2012 at 22:41
  • 1
    @MartinSchröder: Only partially, if you read through egreg's answer. There is no mention of it not supporting xparse definitions, nor does it contain the detail provided by his answer.
    – Werner
    Dec 26, 2012 at 0:40

1 Answer 1

81

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.

5
  • 2
    Say I don't want to take risks!. Can I use \LetLtxMacro for all instances (everywhere)? Will it hurt if done so? (I read your first line but want confirmation)
    – user11232
    Dec 23, 2012 at 12:01
  • 2
    @HarishKumar If the macro is not risky, then \LetLtxMacro does nothing different from \let.
    – egreg
    Dec 23, 2012 at 12:03
  • 2
    Thanks for the warning. I assume, I’m not the only one, who did not know this.
    – Speravir
    Dec 23, 2012 at 19:17
  • Maybe worth mentioning \NewCommandCopy and friends. Jun 7, 2021 at 8:40
  • @BrunoLeFloch Certainly so!
    – egreg
    Jun 7, 2021 at 10:33

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.