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 \expandafter
s:
\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.
\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).