I have already seen the related page macros - What is the difference between \let and \edef?, but I'm afraid it still doesn't expain to me the following MWE:



\tmpb           % typesets "ello AH"
\typeout{\tmpa} % writes "\tmpa" in terminal
\typeout{\tmpb} % writes "A\tmpa" in terminal

This is how I understand it:

  • \let\tmpa= sees first character of Hello, H - it sees it as a single token and gets assigned to it (that is, \let\tmpa=H)
  • The remaining characters ("ello") from \let\tmpa=Hello "fall through" and get typeset (the "ello" in "ello AH")
  • \edef\tmpb{A\tmpa} runs => since \tmpa=H, then \tmpb should expand to "AH"
  • \tmpb runs => as expected, "AH" is typesed after the previous "ello"

And the confusion comes from \typeout{\tmpa} - from the typeset output, I'm pretty sure \tmpa=H; so I expect \typeout{\tmpa} to result with H, but it doesn't - and instead it writes again \tmpa! Same thing if I try to expand it via \edef and throw it in another command (\tmpb), and then I try to \typeout that command.

Why does \typeout in this case not show the "expanded" value of \tmpa? How can I get \typeout to show the expanded value of \tmpa?

Ah well, I asked this question; then I asked myself for it to be closed, given that Showing expanded \let command with \typeout generally provides an answer; in the meantime I came up with an answer I wanted to document - but now I cannot anymore, because it's closed :/ So I posted the answer in macros - How do I ‘expand’ a control sequence \let to a character?; but that answer simply doesn't belong there.

Then finally I realized I can edit my question post, even if it is closed (I just cannot add an answer) - so better to delete the answer from the other question, and move it here I guess (although now that it is here, it would have been better it's an answer :/ Ah nevermind).

So, not to nag the mods to reopen and reclose again, I'll post that answer here:

Basically, to \typeout the contents of that example:

  • Use \meaning to convert \tmpa to "The letter H"
  • Use a "parser" macro, to extract the third word from a set of three words

So finally we have the corrected MWE, that can print the content of \tmpa (given here we explicitly expect it to be one letter) to terminal:



\def\wordIIIofIII #1 #2 #3{#3}

\tmpb           % typesets "ello AH"
\typeout{\tmpa} % writes "\tmpa" in terminal
\typeout{\tmpb} % writes "A\tmpa" in terminal

\typeout{\tmpc}         % writes "the letter H" in terminal
\typeout{\tmpd}         % writes "H" in terminal

\typeout{\the\catcode`H}                  % 11
% \typeout{\the\catcode`\tmpd} % "! Improper alphabetic constant."
\typeout{\the\catcode\expandafter`\tmpd}  %11

  • 1
    Keep in mind that \let must be followed by a control sequence (or an active character), an optional = and one token! Other tokens following the first won't belong to the \let instruction.
    – egreg
    Commented May 28, 2012 at 8:33

1 Answer 1


The syntax for the \let primitive is


where <cs> is a control sequence or active character, <token> is a single token and = can be omitted or surrounded by optional spaces. So

\let\? =H
\let\? = H
\let\? H

are all equivalent (I used \? so that no space is ignored in the tokenization stage).

The so defined <cs> inherits all the characteristics of the <token> (but depending on the token it may or may not be always used as a substitute). In particular, after


the token \tmpa will be unexpandable, just because H is unexpandable.

The command \typeout uses the \write mechanism, which does expansion, but using an output stream that is never assigned a file, so the result is written on the terminal and the log file, also adding an instruction so that \protect does its work correctly (for instance \typeout{\itshape} prints \itshape, while \write255{\itshape} would explode).

Under \write, unexpandable tokens are written by their name. And it's good it's this way: after \write\@outputstream{\bgroup}, finding out { in the output may be disastrous. Similarly one could have good reasons for writing out \tmpa instead of H.

The strategy with \meaning is correct, but it works only in this particular case and it would fail with \bgroup, whose meaning is

\bgroup=begin-group character {

You may find it useful to look at the expl3 function \tl_analysis_show:N; compiling the following file


\tl_analysis_show:n { \tmpa }

will show on the terminal

The token list contains the tokens:
>  \tmpa (control sequence=the letter H).

(For releases before TeX Live 2017, you will need \usepackage{l3tl-analysis} in addition to \usepackage{expl3} for this to work and \tl_show_analysis:N, now a deprecated command.)

Why isn't your \typeout{\the\catcode`\tmpd} working? Because an alphabetic constant is `<character> (where <character> may also be <backslash><character>) and after the backquote a multiletter control sequence is found, which is illegal.

The line \typeout{\the\catcode\expandafter`\tmpd} works, because \catcode expands tokens until finding something that can start a <number> (if not found, TeX raises an error). So the \expandafter is expanded.

  • Thanks for the answer, @egreg - didn't realize it was posted until now. Cheers!
    – sdaau
    Commented Jun 2, 2014 at 23:11

You must log in to answer this question.

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