8

I was surprised to find that the argument of an \unexpanded is expanded if the \unexpanded is within the first two tokens after an \if. Using Knuth TeX's \noexpand instead works but I am curious where the difference is.

\documentclass{article}

\begin{document}

    \def\endtoken{~}
    
    \typeout{! ========== tracing 1 ==========}
    \tracingmacros=2
    \tracingcommands=3
    
%   \if \expandafter\noexpand\endtoken \noexpand~% this would work
    \if \unexpanded\expandafter{\endtoken} \noexpand~% this does not
        true
    \else
        false
    \fi
    
    \tracingcommands=0
    \tracingmacros=0
    \typeout{! ========== tracing 0 ==========}

\end{document}

The \expandafter which expands the argument of the \unexpanded once makes no difference. ~ is expanded all the way with or without it and the result is the same.

\tracingmacros shows how ~ is expanded and \tracingcommands shows that \if evaluates to true. I am assuming that it comes to this result by comparing \protect and \unhbox which are both inserted by expanding ~ and are equal because they are both control sequences. Is there a tracing command which would show which tokens TeX compares when evaluating a conditional? (I have scanned through the great list of tracing commands but have not found this among it unfortuantely.)

(The exclamation mark at the beginning of the \typeout makes TeXstudio think there was an error so that it provides me with a link to the position in the log file where the output of the tracing commands begins and ends. This may, however, have the unintended side effect that it does not load the pdf although it has been built correctly.)

Why is the argument of \unexpanded expanded after an \if (not inside of an \edef) but a token following a \noexpand is not expanded, even after an \if?

The interesting question Get the lion to run in loops. Tersely. also deals with \if and \unexpanded but I think it does not answer this question because there the \fi is in the <filler> of \unexpanded but here after the <balanced text> and the closing curly brace.

5
  • I think the difference between \noexpand and \unexpanded is worth detailing, but @egreg is right that the test here is ... not really correct
    – Joseph Wright
    Jun 27, 2019 at 10:44
  • Side note, basically, if I understood correctly \edef etc. "hard code" \the\toks etc. to insert the content verbatim, so • first, # are not halved • even if you do \edef\something{\expandafter\empty\unexpanded{...}}, \unexpanded loses its magic even if it's inside an edef.
    – user202729
    Jul 11, 2022 at 6:04
  • @user202729 to explain in more detail what's going on in your example: First the \edef expands the \expandafter which expands the \unexpanded. During this expansion \unexpanded does it's magic but that has no effect because \expandafter expands only a single token. Then \edef continues to expand the remaining tokens, first the \empty and then the ... which is now unprotected because the \unexpanded has been removed by the \expandafter. (The curly braces have been removed when expanding the \unexpanded.)
    – jakun
    Jul 13, 2022 at 7:05
  • No, it's not "\expandafter expands only a single token", it's that "\unexpanded (like \the\toks) only protects the content inside when it's in a \edef". If you do \expandafter\empty\romannumeral ..., arbitrarily many tokens after \romannumeral will be expanded until a complete number is formed.
    – user202729
    Jul 13, 2022 at 7:16
  • true, \def\bar{2} \romannumeral1\unexpanded{\bar} expands \bar and so does \expandafter\show\csname foo\unexpanded{\bar}\endcsname. Thanks for pointing that out. Guess I still haven't really gotten used to \unexpanded.
    – jakun
    Jul 16, 2022 at 6:32

1 Answer 1

10

The \unexpanded primitive is essentially an anonymous toks, which means no expansion within an \edef or similar, whereas \noexpand explicitly changes the behaviour of the next token to be equal to \relax for one expansion. This is perhaps easier to see if we choose to typeset the results of the two:

\documentclass{article}
\begin{document}
\newcommand{\demo}{FOO}
Text \noexpand\demo\space text \unexpanded{\demo} text.
\end{document}

The first \demo is turned into \relax for this reading, and so does nothing. In contrast, the second is effectively passed through \toks0{\demo}\the\toks0, and so typesets normally.


As egreg points out, one can also see the effect in

\documentclass{article}
\begin{document}
\expandafter\edef\expandafter\foo\expandafter{\unexpanded{~}} 
\show\foo
\expandafter\edef\expandafter\foo\expandafter{\noexpand~}
\show\foo
\end{document}
3
  • In expl3 code this is important where we return tokens protected from expansion: we always use \unexpanded in case we are not inside an e/x-type context.
    – Joseph Wright
    Jun 27, 2019 at 10:45
  • Do I understand it correctly that \unexpanded behaves as if it would save the balanced text in a toks register (as described in TeX by Topic Chapter 14: Token Lists) and then inserts it like with a \the (except that this does not influence any of the registers that you can access with \the)? So the balanced text is not expanded if \unexpanded is expanded by \edef (or \xdef) but expanded anywhere else?
    – jakun
    Jun 27, 2019 at 12:15
  • @jakun Exactly: the code is that for a toks, just without the need to assign to a real one
    – Joseph Wright
    Jun 27, 2019 at 12:25

You must log in to answer this question.

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