There is the following snippet of code in pgfutil-common.tex (with a very
similar snippet in pgfmathutil.code.tex`):
{%
\def\:{\global\let\pgfutil@sptoken= } \:
\def\:{\pgfutil@xifnch} \expandafter\gdef\: {\futurelet\pgfutil@let@token\pgfutil@ifnch}
}
I've been trying to understand this by means of writing my own version:
\documentclass{article}
\makeatletter
\newcommand\aetest{\ae@test}
\def\ae@test(#1){%%
\textsf{#1}%%
\ae@ifnextchar H%%
{\ae@true}{\ae@false}}
\def\ae@true#1;{ \textbf{(true):#1}}
\def\ae@false#1;{ \textbf{(false):#1}}
\long\def\ae@ifnextchar#1#2#3{%%
\let\ae@reserved@d=#1%%
\def\ae@reserved@a{#2}%%
\def\ae@reserved@b{#3}%%
\futurelet\ae@let@token\ae@ifnch}
\def\ae@ifnch{%%
\ifx\ae@let@token\ae@sptoken
\let\ae@reserved@c\ae@xifnch
\else
\ifx\ae@let@token\ae@reserved@d
\let\ae@reserved@c\ae@reserved@a
\else
\let\ae@reserved@c\ae@reserved@b
\fi
\fi
\ae@reserved@c}
{%%
\def\:{\global\let\ae@sptoken= } \:
\def\:{\ae@xifnch} \expandafter\gdef\: {\futurelet\ae@let@token\ae@ifnch}%%
}
\makeatother
\begin{document}
\aetest(This test is) Hello;
\aetest(This test is) Ciao;
\end{document}
The above code compiles correctly and as expected.
The mentioned snippet has been rewritten as:
{%%
\def\:{\global\let\ae@sptoken= } \:
\def\:{\ae@xifnch} \expandafter\gdef\: {\futurelet\ae@let@token\ae@ifnch}%%
}
I believe I understand what this snippet is supposed to do:
(a) \let the token \ae@sptoken to a space token
(b) Scan ahead over any space token in the token list to the next non-space token.
I have two questions:
(1) Why the need to use \: instead of some other control sequence?
(2) Why isn't the space following \expandafter\gdef\: eaten after expansion?
On page 39 of The TeXBook, Knuth writes:
.... spaces are not ignored after control sequences inside a token list; the ignore-space rule applies only in an input file, during the time that strings of characters are being tokenized.
Because of this, I thought I could rewrite the first line of this snippet as:
\def\ae@colon{\global\let\ae@sptoekn= }\ae@colon
I was under the impression that, since the space after the equal sign has
already been tokenized, it wouldn't be lost. But what seems to be happening is
that when \ae@colon is expanded, this tokenized space is irrelevant. Instead,
\ae@sptoken is \let to \def. Though I'm not sure how to verify this or
not, LaTeX just complains that \ae@xifnch is undefined. Hence my first question.
Regarding \expandafter\gdef\: and the following space: I was thinking that
this space should be lost since \: is expanded before the space is tokenized.
Therefore I thought one of the following might work:
\expandafter\gdef\:{....} %%<-- no space following "\:"
or
\gdef\ae@xifnch{....}
or
\gdef\ae@xifnch {...} %%<-- space after \ae@xifnch
But neither work. Instead, LaTeX hangs. I assume that's because it keeps parsing the same space token and is unable to remove it from the list.
So somehow when \expandafter\gdef\: is expanded, the following space is
preserved. Hence my second question.
Regarding the choice of a colon, I know there's nothing special with \:. I've
experimented with \! and \,. Both work perfectly fine. So, the trick here
has something to do with how control symbols (control sequence consisting of one
non-letter) work. But, I'm somehow missing how \: is achieving the desired
effect here.
\gdef\:. If we use name other than one non-letter, a space is ignored, because it only terminates the name. – Przemysław Scherwentke Jul 08 '14 at 23:32\expandafter\gdef\:*where by*I'm referring to the space. – A.Ellett Jul 08 '14 at 23:35\expandafter, why are\expandafter\gdef\:*{...}and \gdef\ae@xifnch*{...}` not equivalent? Shouldn't that space still be getting eaten? – A.Ellett Jul 08 '14 at 23:43\expandafter\gdef\:*expands to\gdef\ae@xifnch*which would consequently ignore that space since it's no longer following a single non-letter token. – A.Ellett Jul 08 '14 at 23:50\@ifnextcharinlatex.ltx(pgfworks without LaTeX so needs its own version here). – Joseph Wright Jul 09 '14 at 05:57