19

After

\def\MyText{\textbf{My Text}}
\let\MySaved\MyText

\MySaved and \MyText have the same \meaning. What I would like to have further down in the document is

% \MyText = \textbf{My Text}
\def\MyText{\textit{More Text}}
\let\MySaved{\MySaved \MyText}
% \MySaved = \textbf{My Text} \textit{More Text}

but obviously \let does not allow a group of tokens in the second argument.

Is there any way to append like this with the same specific (non-)expansion properties \let has?

1
  • What do you mean by non-expansion properties of \let? It just assigns the meaning of one token to another, and expansion does not enter into the question. But neither does \def\MySaved{\MySaved \MyText} expand anything (but just like \let it makes the previous meaning of \MySaved be forgotten, which is probably not what you want). Apr 24, 2014 at 6:05

3 Answers 3

27

\def with \expandafter help:

\expandafter\def\expandafter\MySaved\expandafter{\MySaved \MyText}

If you are using LaTeX (\textbf, \textit, ...), then \g@addto@macro can be used:

\makeatletter
\g@addto@macro\MySaved{\MyText}
\makeatother

Or if you need complete expansion:

\edef\MySaved{\MySaved \MyText}

But that might break fragile stuff, thus LaTeX provides \protected@edef:

\makeatletter
\protected@edef\MySaved{\MySaved \MyText}
\makeatother

Or if \Mysaved and \MyText should be expanded once exactly, e-TeX's \unexpanded helps:

\edef\MySaved{%
  \unexpanded\expandafter{\MySaved}%
  \unexpanded\expandafter{\MyText}%
}

The same can be achieved by token registers in vanilla TeX:

\toks0\expandafter{\MySaved}
\toks2\expandafter{\MyText}
\edef\MySaved{\the\toks0 \the\toks2}
1
  • Interestingly enough, only the \unexpanded method yielded the expansion I was looking for - works perfectly!
    – arney
    Apr 23, 2014 at 16:17
21

Without reinventing the wheel, we can use etoolbox:

\appto{\MySaved}{\textit{More text}}

with \gappto if the change should be global. If you want to add to \MySaved the (first level) expansion of \MyText, there's

\eappto{\MySaved}{\expandonce{\MyText}}

and \xappto will do the same globally. Let's see:

\documentclass{article}
\usepackage{etoolbox}
\def\MyText{\textbf{My Text}}
\let\MySaved\MyText
\def\MyText{\textit{More Text}}
\eappto\MySaved{\MyText}
\show\MySaved

The output on the terminal will be

> \MySaved=macro:
->\textbf {My Text}\textit {More Text}.

To make the thing more symmetric, you can use

\eappto{\MySaved}{\expandonce{\MyText}}

also in place of \let, but this wouldn't reinitialize \MySaved.

If only Plain TeX is wanted, just copy the implementation:

\protected\def\appto#1#2{%
  \ifundef{#1}
    {\edef#1{\unexpanded{#2}}}
    {\edef#1{\expandonce#1\unexpanded{#2}}}}
\protected\def\eappto#1#2{%
  \ifundef{#1}
    {\edef#1{#2}}
    {\edef#1{\expandonce#1#2}}}
\protected\def\gappto#1#2{%
  \ifundef{#1}
    {\xdef#1{\unexpanded{#2}}}
    {\xdef#1{\expandonce#1\unexpanded{#2}}}}
\protected\def\xappto#1#2{%
  \ifundef{#1}
    {\xdef#1{#2}}
    {\xdef#1{\expandonce#1#2}}}
\def\ifundef#1{%
  \ifdefined#1%
    \ifx#1\relax
      \expandafter\expandafter
      \expandafter\@firstoftwo
    \else
      \expandafter\expandafter
      \expandafter\@secondoftwo
    \fi
  \else
    \expandafter\@firstoftwo
  \fi}
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\def\expandonce#1{%
  \unexpanded\expandafter{#1}}
8

Since the question is about plain TeX, I would suggest using token list registers for this rather than macros, since token lists are there specifically for this purpose, namely to hold token lists. Create one with

\newtoks\MyList

Assign an explicit list to it by for instance

\MyList={\textbf{My text}}

or any other (balanced) token list between the braces; since this is about gathering tokens, you can be sure there is no attempt to expand anything there. Unlike macros, token list registers do no spontaneously expand to the tokens they hold (if TeX encounters the name of a token list register when expecting an action, it will assume this starts an assignment to the register, and protest if no opening brace follows), so to get at the contents, you must explicitly expand with \the. Hence if at the end of the day you want to transfer the tokens to become the body of a macro, you can say

\edef\macro{\the\MyList}

(the \edef is used because the contents of \MyList is wanted here and now, not later when \macro gets expanded). Note that even though \edef usually keeps expanding as far as it can, the result of \the applied to a token list register is explicitly excluded from any further expansion attempts, so you can be sure that \macro will expand to exactly the tokens that were collected in \MyList.

Now to extend to contents of a token list register is fairly simple; you must just ensure the the old contents gets to be expanded into the new token list before the assignment is made. For this a single \expandafter will do:

\MyList=\expandafter{\the\Mylist more tokens here}

When you need to expand something towards the end of the token list, it takes a bit more effort. Say you want to append to the contents of \MyList that of another token list register \AnotherList. Then you could ensure that the rightmost list gets expanded, and then the leftmost one (can you see why this order is necessary?), all this before the assignment takes place, by a whole slough of \expandafters:

\let\x=\expandafter
\MyList=\x\x\x{\x\the\x\MyList\the\AnotherList}

However there is an easier way, that mixes the expansive nature of \edef and the passive nature of token lists to get detailed control over expansion. It needs an auxiliary macro, say \temp:

\edef\temp{\the\MyList\the\AnotherList}
\MyList=\exandafter{\temp}

I final remark about the question; you suggest that \let serves to copy the expansion of one macro to another macro without further expanding that expansion (as using \edef would do). While \let can be used for that, this is not its main purpose, and in fact this is just a corollary of what \let does in general: transfer the current meaning of one token to another one (provided the latter can have its meaning modified, so it should not be a non-active character). This is not limited to macros: you can make a control sequence stand for a plain character, or for a TeX primitive (as I did above to let \x stand for the primitive \expandafer; note that having instead \x expand to \expandafer would be quite different and quite useless) or for other meanings that a token can have. Just as an example of the last possibility, saying

\let\newname=\MyList

would transfer the current meaning (not the contents!) of \MyList to \newname. Since \MyList stood for an internal token list register of TeX, this makes \newname stand for the same register: it becomes an alias for \MyList, and assigning to one of them changes the contents of the other as well.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .