The conditional \ifx
compares the following two tokens and returns true if they are the same as far as \show
is concerned. So two identical characters (by character code and category code), or two macros having the same status with respect to \long
(and \protected
if e-TeX is used) and the same first level expansion, or the same TeX primitive (one or both can be control sequences \let
to the primitive). A control sequence \let
to a character will be considered the same as the character.
In the case of \e\h\f
, \e
finds its argument to be \h
, so TeX replaces the first two tokens and gets
\ifx\f\h•e•\else\h•\fi\f
(here •
denotes a space token). The test returns false, so TeX removes everything up to and including the matching \else
. What remains at the next stage is
\h•\fi\f
and now \h
finds its argument to be \fi
(space tokens are ignored when looking for an undelimited argument), and the next stage is
h\f
Then TeX typesets h
, expands \f
that prints f
and warns about an incomplete conditional, because there's no \fi
any more:
\end occurred when \ifx on line 12 was incomplete
(the line number will of course be different).
On the contrary, \e\s\f
will become
\ifx\f\s•e•\else\s•\fi\f
and then
\s•\fi\f
Since the expansion of \s
is empty, you get
•\fi\f
and the space is typeset, the \fi
is expanded (producing nothing, but keeping TeX happy about the count of conditional) and \f
produces an ‘f’. Indeed, the output of [\e\s\f]
is
[ f]
With \e\f
the replacement gives
\ifx\f\f•e•\else\f•\fi
and the test returns true. In this case, TeX just removes the \ifx
and the test tokens; the next stage is so
•e•\else\f•\fi
so “space e space” is printed; then \else
removes everything up to the matching \fi
. Indeed, the output of [\e\f]
is
[ e ]
You should be more careful about spurious spaces and also pushing \else
and \fi
out of the way.
Ulrike's solution is good, and no space is added. However, if you want to have a fully expandable macro, do
\newcommand{\e}[1]{% eat
\ifx\f#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{e}%
{#1}%
}
but be sure to provide a non empty argument to \e
. A different strategy is to compare the tokens with expl3
:
\usepackage{xparse} % loads expl3
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\e}{m}
{
\token_if_eq_meaning:NNTF \f #1 { e } { #1 }
}
\ExplSyntaxOff
Full code
\documentclass{article}
\usepackage{xparse}
\newcommand{\f}{f}% food
\newcommand{\s}{}% stop eating
\newcommand{\h}[1]{h}% hide food
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\e}{m}
{
\token_if_eq_meaning:NNTF \f #1 { e } { #1 }
}
\ExplSyntaxOff
\begin{document}
% f represents food
% e represents eaten food
% Eat food
[\e\f]% [e]
% Stop eating
[\e\s\f]% [f]
% Hide food
[\h\f]% [h]
% Eat hidden food
[\e\h\f]% [h]
\end{document}
[\e{\h\f}]
so\e
captures\h\f
and not just\h
.