11

I have a very simple question. When I do this:

\catcode`\@=0
\catcode`\\=11
@mycommand{a}
@catcode`@\=0
\catcode`\@=11

It works perfectly and calls \mycommand correctly. However, when I try to define \mycommand with similar trickery:

\newcommand\mycommand[1]{
  \catcode`\@=0
  \catcode`\\=11
  @textbf{Hello #1}
  @catcode`@\=0
  \catcode`\@=11
}

compilation stalls and gives me the * prompt. If I give it Ctrl+D, it terminates without producing any output. Indeed, it seems that changing the catcodes inside a command has no effect whatsoever, because the following works perfectly (whereas, from my understanding, it shouldn't):

\newcommand\mycommand[1]{
  \catcode`\@=0
  \catcode`\\=11
  \textbf{Hello #1}
}

Can anybody please explain to me what's happening?

10

When you say

\newcommand\mycommand[1]{
  \catcode`\@=0
  \catcode`\\=11
  @textbf{Hello #1}
  @catcode`@\=0
  \catcode`\@=11
}

TeX stores the following tokens as replacement text for \mycommand (the • bullet separates tokens and spaces are used for legibility, <sp> denotes a space token):

<sp> • \catcode • ` • \@ • = • 0 • <sp> •
\catcode • ` • \\ • = • 1 • 1 • <sp> •
@ • * t • e • x • t • b • f • { • H • e • l • l • o • <sp> • #1 • } • 
@ • c • a • t • c • o • d • e • ` • @ • \= • 0 • <sp> •
\catcode • ` • \@ • = • 1 • 1 • <sp>

where

  • @, `, 0, 1 and = have category code 12,
  • { and } have category code 1 and 2 respectively,
  • <sp> has category code 10,
  • the letters have category code 11.

The category codes are frozen once they have entered TeX's mouth. When the macro \mycommand{Worlds} is expanded, TeX will change the category code for all @ it will absorb from that point on (respecting groups), but this can't change in any way what has already been tokenized, for instance the sequence of tokens

@ • * t • e • x • t • b • f

that have already been stored.

Something will be printed, precisely

@textbfHello World @catcode‘@0

(the 0 will have a bar over it) and TeX won't have any character with category code 0 meaning it won't recognize commands.

I'll do an example in Plain TeX, which is easier to print, but essentially equivalent. I'll only add \csname bye\endcsname to end the game:

\def\mycommand#1{
  \catcode`\@=0
  \catcode`\\=11
  @textbf{Hello #1}
  @catcode`@\=0
  \catcode`\@=11
  \csname bye\endcsname
}

\mycommand{World}

enter image description here

Remember that when TeX executes \def, it completely disables macro expansion and command execution of the tokens it absorbs for the macro name, the parameter text and the replacement text. It will only expand the tokens in the replacement text but again not execute them when it's doing an \edef.

  • In other words: This question here is a duplicate of the one linked by @cfr? – Speravir Jan 5 '14 at 0:36
  • @Speravir I don't think so. This one has different subtleties. – egreg Jan 5 '14 at 0:37
  • Thanks for the explanation. What I don't get, though, why would the @ in @textbf be "already tokenized" with catcode 12 when I have explicitly redefined its catcode to be 0 only 2 lines before? – Joseph R. Jan 5 '14 at 0:40
  • OK. I just thought so while reading your “respecting groups” and “category codes are frozen”. – Speravir Jan 5 '14 at 0:41
  • 2
    @JosephR. You don't have executed the category code change, just stored in a macro the instruction to do it; TeX never expands or executes tokens when it's absorbing the replacement text of a macro (with \def; it expands tokens but doesn't execute them with \edef). – egreg Jan 5 '14 at 0:42

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.