Why can I not use \string to prevent the expansion of \csname?
\immediate\write\@mainaux{\gdef \string\saveForLater{123}}
This should work since it saves \gdef\saveForLater{123}
in the .aux.
\immediate\write\@mainaux{\string\expandafter\gdef\string\csname saveForLater\string\endcsname{456}}
The problem there is that you are saving \expandafter\gdef \csnamesaveForLater\endcsname{456}
in the .aux, because \string
doesn't add a space after outputting the control sequence name. So when you read again and see \csnamesaveForLater
TeX doesn't know what that is. You would need \string\csname\space
. But I don't know what you intend, simpler seems
\immediate\write\@mainaux{\gdef\expandafter\string\csname saveForLater\endcsname{456}}
which saves \gdef\saveForLater{456}
. If that's not what you intend, you need that \space
there.
Or, as you've already seen, use \noexpand
.
Recall that \write
does complete expansion until unexpandable tokens remain (when the write operation actually takes place). Since \gdef
is unexpandable, it needs not be preceded by \string
, unless you want to avoid a space following it.
There is a timing problem with your code (let me omit \immediate
that's irrelevant here):
\write\@mainaux{\string\expandafter\gdef\noexpand\csname saveForLater@\somedef\string\endcsname{456}}
- the token
\string
is expandable, so it acts on the following token (\expandafter
) \gdef
is not expandable\noexpand
is expandable, so it acts on the next token (\csname
)- the characters in
saveForLater@
are unexpandable \somedef
should expand to character tokens, let's say it expands tofoo
\string
is expandable, so it acts on the next token (\endcsname
)- the characters in
{456}
are unexpandable.
Thus what you get written is
\expandafter\gdef \csname saveForLater@foo\endcsname{456}
With \string\csname
you'd get
\expandafter\gdef \csnamesaveForLater@foo\endcsname{456}
because there is no space following \csname
in the token list passed to \write
.
Why is there one with \noexpand
? For the same reason there is one after \gdef
: TeX adds a space following an unexpandable control word when it performs a write operation. With \noexpand\csname
the normally expandable \csname
is made temporarily equivalent to \relax
, so it gets written with a space following it, just like \relax
would (or \gdef
).
\immediate\write\@auxout{%
\gdef\expandafter\noexpand\csname saveForLater@\somedef\endcsname{456}%
}
will write
\gdef \saveForLater@foo {456}
because \expandafter
causes the control sequence being formed by \csname
before \noexpand
can act on it.
If you want to preserve the \csname
in the .aux
file:
\immediate\write\@auxout{%
\noexpand\expandafter
\gdef\noexpand\csname saveForLater@\somedef\endcsname{456}%
}
that will write
\expandafter \gdef \csname saveForLater@foo\endcsname {456}