As the title says: is there any completely reliable, expandable method to differentiate between a control sequence that has been made equivalent to a character token and the character token itself? (Assuming the meaning of particular primitives was not changed: otherwise clearly all bets are off.) For example, consider the following (staying with plain TeX to keep superfluous elements to the minimum):
\font\ecrm=ecrm1000 \ecrm
\long\def\test#1#2{\hbox{%
\vbox{\hsize=15em\escapechar=`\\ \tt\detokenize{#1}}%
\vbox{#2}\par%
}}
\long\def\testexp#1{\test{#1}{#1}}
\long\def\testif#1{\test{#1}{#1\else not \fi equal}}
\long\def\exec#1{{\escapechar=`\\ \tt\detokenize{#1}}#1\par}
\begingroup
\exec{\let\^=^}
\exec{\escapechar=-1}
\bigskip
\testexp{\meaning^}
\testexp{\meaning\^}
\testexp{\string^}
\testexp{\string\^}
\testexp{\detokenize{^}}
\testexp{\detokenize{\^}}
\bigskip
\testif{\if^\^}
\testif{\if^\noexpand\^}
\testif{\ifcat^\^}
\testif{\ifcat^\noexpand\^}
\testif{\ifx^\^}
\bigskip
\exec{\def\tmpa{^}\def\tmpb{\^}}
\testif{\ifx\tmpa\tmpb}
\endgroup
\bye
(For convenience I do use the ε-TeX primitive \detokenize
here, but that is not the primary point, hence the tex-core tag.)
I have found no way to make any of the conditionals recognize the difference between the two tokens: the actual character token and the control sequence. (I knew that these were not supposed to differentiate between them, but went and tested them just in case.) If I additionally assume that \escapechar
is not printable, as is the case here then not even \meaning
, \string
, or \detokenize
will treat them any differently.
That said, the TeX engine clearly does know the difference, as when these are made to be the replacement text of macros, \ifx
recognizes them as not the same. Likewise when they are set as delimiters of macro arguments. However, if we want an expandable comparison of the two tokens as, say, the arguments of a macro, then this is not something we can do. Neither can we change the value of \escapechar
: if it is not printable, we are stuck with it.
Is there a way to make the comparison in an expandable manner, one I have not thought of? If not in (e)TeX, then maybe in XeTeX or LuaTeX?
P.S. Another, somewhat related, weird corner case of tokens that I find are hard to tell apart: the control sequence with the empty name and — assuming, say, the normal escape character — the one with the name csname\endcsname
(which is a situation where I really fail to comprehend TeX going out of its way change the rules for that one special case, messing up the injectivity of \string
on macros). I know that LuaTeX’s \csstring
does kind of solve that though.
Best Answer
David's solution expects that you will compare something with the fixed token
^
. You cannot redefine the \testifhatx to something other at expansion level only. My solution works with two arbitrary tokens, not only with^
and another one.Edit I created a second version, whereby you can process something like
\fi
in the parameter, as per your comment.