15

I do not understand how \ifx interacts with macro definitions. Here is a minimal example:

\def\a#1{\b}
\def\b#1#2{[#1:#2]}
\a ABC

The output is [B:C], as expected. If I change the definition of \a to

\def\a#1{\ifx E#1\else \b\fi}

then the output becomes [:B]C. Where does the empty argument to \b come from, and how do I get rid of it?

I apologize for asking a question that surely has been asked on this site before. I tried hard to find the answer, but in vain. Thanks!

13

With

\def\a#1{\ifx E#1\else \b\fi}

the call \a ABC takes A as the argument to \a, so the input stream becomes

\ifx EA\else\b\fi BC

and, since the condition turns out to be false, what remains in the input stream is

\b\fi BC

Thus the arguments to \b are #1<-\fi and #2<-B, so we get

[\fi:B]C

Now \fi performs its duty of disappearing and you get

[:B]C

If instead you define

\def\a#1{\ifx E#1\else\expandafter\b\fi}

after the conditional we get

\expandafter\b\fi BC

The \expandafter makes \fi disappear before \b is expanded, so we find

\b BC

and finally

[B:C]

In the case of \a EBC, the first step would give

\ifx EE\else\b\fi BC

that turns into

\else\b\fi BC

The expansion of \else throws out everything up to the matching \fi and we simply get

BC

Looking at the log file with \tracingmacros=1 helps:

\tracingmacros=1
\def\a#1{\ifx E#1\else \b\fi}
\def\b#1#2{[#1:#2]}
\a ABC

will produce

\a #1->\ifx E#1\else \b \fi 
#1<-A

\b #1#2->[#1:#2]
#1<-\fi 
#2<-B

that shows precisely what I diagnosed without doing the experiment.

If you add also \tracingifs=1 (with an e-TeX based engine such as pdftex), you get

\a #1->\ifx E#1\else \b \fi 
#1<-A
{vertical mode: \ifx: (level 1) entered on line 4}
{\else: \ifx (level 1) entered on line 4}

\b #1#2->[#1:#2]
#1<-\fi 
#2<-B
{horizontal mode: \fi: \ifx (level 1) entered on line 4}
  • Thanks! I am too used programming in conventional languages. It all makes sense now! – Boris Bukh Oct 6 '14 at 21:34
  • @BorisBukh It takes a while understanding how conditional work in TeX; a true conditional just removes itself, leaving the duty of getting rid of the false branch to \else; a false conditional removes itself and anything up to (and including) the matching \else. – egreg Oct 6 '14 at 21:38
6

\b grabs the \fi but if you use the following definition of \a, the you obtain the expected output:

\def\a#1{\ifx E#1\else \expandafter\b\fi}

The above completes the conditional \if..\fi before processing \b.

enter image description here

\documentclass{article}
\begin{document}

\def\a#1{\b}
\def\b#1#2{[#1:#2]}
\a ABC

\def\a#1{\ifx E#1\else \b\fi}
\a ABC

\def\a#1{\ifx E#1\else \expandafter\b\fi}
\a ABC

\end{document}​

If you wish to see this, use the following definition of \b and check your .log for the values contained in \argA and \argB:

\def\b#1#2{%
  \def\argA{#1}\show\argA%
  \def\argB{#2}\show\argB%
  [#1:#2]}

For the second call to \a above, you'll find

> \argA: macro
-> \fi .
> \argB: macro
-> B.

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.