1

This is a tangential followup to my question here: How do things like ToC and label work to save information between compiles?

Edit: Question solved but the original was ill formed. I have edited the question to reflect the solution.

I am fairly familiar with a lot of expansion aspects of latex, but I only know how to avoid a particular macro from expanding, or skipping macros during expansion using \expandafter. But is there a way to immediately define a macro when it is defined, but without expanding any commands in that macro? Let me give an example.

Suppose I know I will be handed some mystery macros \text, \texttwo, \textthree. All I know is that they contain text and some number of commands, but I have no idea what those commands are.

I want to write a macro that transfers the content of the mystery macro to a new name I have, so I can renew the previous mystery macro. But I need it to do so immediately so that, as I renew the mystery macro, I can use transfer on it several times, renewing it between uses, and not end up with a bunch of duplicate macros at the end. So, some pseudo code would be;

\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}

\newcommand{\transfer}[2]{%
    \expandafter\let\csname#2\endcsname#1% \let works better than \edef
}%
\begin{document}

\transfer{\text}{newcomone}
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\transfer{\text}{newcomtwo}
\renewcommand{\text}{New Text Take three, but with \textthree}
\transfer{\text}{newcomthree}

\text

\newcomone

\newcomtwo

\newcomthree
\end{document}

Ideally I'd want the output to look like;

New Text Take three, but with Mysterious content here again and again
Mysterious content here
New Text Take two, but now include Mysterious content here again
New Text Take three, but with Mysterious content here again and again

In the above example I (originally) used edef, but I don't want to use edef directly as that would expand the commands inside \newcomtwo and \newcomthree. But I believe if I used \def it would result in all three being the same.

Now, if I knew the commands coming in I could use \noexpand or \protect in front of the relevant commands (ie write something like \renewcommand{\text}{New Text Take two, but now include \protect\texttwo} ) But is there a way to do it without needing access to the mystery command? i.e. do it at the level of how I defined the \transfer command?

  • \let\origmacro\macro \renewcommand\macro{...}? – cfr Sep 7 '17 at 1:41
  • Since Mysterious Text! is nowhere in your file at all, how is that supposed to be produced exactly? – cfr Sep 7 '17 at 1:46
  • You code gives a fatal error. – cfr Sep 7 '17 at 1:48
  • Sorry about that, fixed the description. How does \let and \edef differ? Is \let just \edef without the internal expansion? – Jason Sep 7 '17 at 1:48
  • The fatal error is inherent in the edef, it's looping trying to expand \texttwo which contains \text, while I'm trying to redef \text. Which was sort of my problem, or at least, a byproduct of my problem. – Jason Sep 7 '17 at 1:50
1

Answer to edited question:

You can simply use \let\newmacroname\oldmacroname \renewcommand\oldmacroname{...} as explained below.

\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\let\newcomthree\text

\text

\newcomone

\newcomtwo

\newcomthree

\end{document}

target output

Which is the output required. I'm not sure why you'd want to define \transfer rather than just using \let. You might just as soon use \let directly - it improves transparency of your code and is less typing, to boot. What's not to like?

Answer to original question:

The problem isn't so much with transferring them as with the definitions themselves.

\let copies a macro. It doesn't expand anything. It is commonly used to save a macro definition which is about to be redefined, typically in a way which makes use of the original.

Using \let, we can copy \text at each point. Using \show we can examine the definitions at each point.

What we can't do is use \newcomtwo or \newcomthree because their expansion now yields a fatal error. But this is not because the copies have not been made faithfully. It is because the concept of the definitions themselves is problematic. When you call \newcomtwo and \newcomthree, they have the correct definitions. But I think you've not thought through what those definitions will be at this point, given that \text now has a completely new meaning.

What you might mean - I'm not sure - is that the original definition of \text should be used. In that case, you can patch your new commands. (But then \edef would be a simpler option, perhaps, so this is probably not what you mean at all.)

\documentclass{article}
\usepackage{etoolbox}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo and \text}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\show\newcomone
\begin{verbatim}
\newcomone=\long macro:
->Mysterious content here.
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\show\newcomtwo
\begin{verbatim}
\newcomtwo=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\let\newcomthree\text
\show\newcomthree
\begin{verbatim}
\newcomthree=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}

\newcomone

\patchcmd\texttwo{\text}{\newcomone}{}{}
\patchcmd\textthree{\text}{\newcomone}{}{}

\newcomtwo

\newcomthree

\end{document}

possible output

\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo and \text}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\show\newcomone
\begin{verbatim}
\newcomone=\long macro:
->Mysterious content here.
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\show\newcomtwo
\begin{verbatim}
\newcomtwo=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\let\newcomthree\text
\show\newcomthree
\begin{verbatim}
\newcomthree=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}

\newcomone

% \newcomtwo

% \newcomthree

\end{document}
0

What \transfer now does is, with the first string of expansions, turns #1 (which is \text) into the macro substitution for \text. The second round of expansions converts \tmp into \csname #2\endcsname, while the final round of expansion turns \csname#2\endcsname into, for example, \newcomone, \newcomtwo and \newcomthree, respectively.

The macros are not fully expanded, as can be seen from the result of my \detokenize invocations.

\documentclass{article}
\usepackage[T1]{fontenc}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo{} and \text}

\newcommand{\transfer}[2]{%
  \def\tmp{\csname #2\endcsname}%
  \expandafter\expandafter\expandafter\expandafter\expandafter%
  \expandafter\expandafter\def\expandafter\tmp\expandafter{#1}%
}%
\begin{document}
\transfer{\text}{newcomone}
\newcommand{\textA}{New Text Take two, but now include \texttwo}
\transfer{\textA}{newcomtwo}
\newcommand{\textB}{New Text Take three, but with \textthree}
\transfer{\textB}{newcomthree}

\detokenize\expandafter{\newcomone}

\detokenize\expandafter{\newcomtwo}

\detokenize\expandafter{\newcomthree}

\bigskip

\newcomone

\newcomtwo

\newcomthree
\end{document}

enter image description here

I had solved the OP's original question above, but with his revised definitions of \texttwo and \textthree (which are simpler because they are not recursive),

\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}

the result is

enter image description here

  • Yes ... but you can't actually use the macros, can you? You'll get a fatal error just as you do with \let. – cfr Sep 7 '17 at 2:09
  • @cfr You can, if you don't keep redefining \text (see edit) – Steven B. Segletes Sep 7 '17 at 2:15

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.