I am aware of this response

Why does \def fail inside \edef?

which explains that \def is unexpandable, and hence subsequent uses of the attempted definitions fail inside an \edef.

I would like to understand why all of the following work as expected:

\edef\x{\expandafter\def\csname y\endcsname{1}\y}
\edef\x{\expandafter\edef\csname y\endcsname{1}\y}
\edef\x{\expandafter\let\csname y\endcsname=1\y}


All of the above work correctly when used alone. In particular,

\edef\x{\expandafter\def\csname y\endcsname{1}\y}


\edef\x{\expandafter\edef\csname z\endcsname{2}\z}


\edef\x{\expandafter\let\csname w\endcsname=3\w}


will produce



\edef\x{\expandafter\def\csname y\endcsname{1}\y}


\edef\x{\expandafter\edef\csname y\endcsname{2}\y}

\x   % where the error appears.

\edef\x{\expandafter\let\csname y\endcsname=3\y}


produces the error

! Missing control sequence inserted.
<inserted text> 
l.33 \x
  • 2
    \csname whatever\endcsname expands to \whatever. If the command is not defined, \whatever is exactly the same as \relax, so in your case after getting \y it doesn't expand further. So you are defining \x three times, first with meaning \def\y{1}\y, second with \edef\y{1}\y, and third with \let\y=1\y. The problem would be if you actually executed those definition by letting \x expand, in which case \y would be defined after the first use so the second definition of \x would be like \edef1{1}1 and when executing \x again it would raise errors. – Manuel May 7 '18 at 22:08
  • @Manuel Your comment should be an answer – egreg May 7 '18 at 22:37
  • Thanks for the comment. Please see the updated question. – dow May 7 '18 at 22:39
  • In the second case you need to jump over the initial \edef\x too – percusse May 7 '18 at 22:46
  • I guess my question is what is the difference between \edef\x{\edef\y{1}\y} and the version that uses \csname... – dow May 7 '18 at 23:17

\csname is expandable, which means that it will do its action in an \edef. The action is to build a control sequence token from the tokens it finds up to the matching \endcsname, performing full expansion as it goes.

Once the action of \csname ends, the token gets expanded or not according to the context; it will, in \edef, provided it is expandable. If it is not expandable, \edef will simply store it in the replacement text it is building and go on to the next token.

Thus the problem is: what token results from \csname y\endcsname? Obviously \y, but now its expandability depends on the meaning \y has.

There are two cases:

  • \y has no previous meaning (that is, it is undefined);

  • \y is already known to TeX.

There are several methods to assign a meaning to a control sequence token: \y can be

  1. a macro (defined with \def, \edef, \gdef or \xdef);
  2. a primitive;
  3. a \countdef, \dimendef, \skipdef, \muskipdef, \toksdef, \chardef, or \mathchardef token;
  4. a font selector (defined with \font);
  5. a token defined with \let.

In case 1 \y is expandable; in case 2 it can be or not, depending on the primitive (for instance \if, \the, \csname are expandable, \relax is not). In cases 3 and 4 \y is not expandable. In case 5, \y inherits the expandability (and definedness) from the token it is \let to.

However, there is a big difference between

\edef\x{... \y ...}


\edef\x{... \csname y\endcsname ...}

when \y has no previous meaning. When a token is built with \csname, if it is unknown, TeX will always assign it the same meaning as \relax (such an assignment is local).

Consider your \edef\x{\expandafter\def\csname y\endcsname{1}\y}, which is the same as \edef\x{\def\csname y\endcsname{1}\y} (because \def is not expandable). Assuming \y has no previous definition, the built token is equivalent to \relax. Indeed, if you add \show\x you will be answered

> \x=macro:
->\def \y {1}\y .

Now if you execute \x, \y will be defined as a macro expanding to 1. A further \edef\x{\def\csname y\endcsname{1}\y} followed by \show\x will print

> \x=macro:
->\def 1{1}1.

Note that the built token has been expanded, because now \y is a macro.

Still no error will be raised, because TeX has simply stored the definition. But if we try to execute \x, we get

! Missing control sequence inserted.
<inserted text> 
<to be read again> 
\x ->\def 1

because \def 1 is illegal.

Your “working” example does not raise errors because \y, \z and \w are undefined tokens when \edef\x{...} is performed.

For completeness, what happens when you do \edef\x{... \y ...} and \y is undefined? You of course get an error of Undefined control sequence when the \edef is being carried out.

| improve this answer | |

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.