13

Why does the \ifx test give a different answer than \ifthenelse in the following simple example?

testclass.cls (without the head and tail):

\newcommand{\isempty}{\@empty}

\ifthenelse{\equal{\isempty}{\@empty}}
   {\newcommand{\foo}{ifthen says yes}}
   {\newcommand{\foo}{ifthen says no}}
\ifx\isempty\@empty
   \newcommand{\foofoo}{ifx says yes}
   \else\newcommand{\foofoo}{ifx says no}
\fi

Now if I call commands \foo and \foofoo in a .tex file, I'll get the following output:

ifthen says yes

ifx says no

Why? Where's the difference? I thought that the following two would be equivalent:

\ifx\macroA\macroB\DoSomething\else\DoSomethingElse\fi
\ifthenelse{\equal{\macroA}{\macroB}}{\DoSomething}{\DoSomethingElse}

Are there some expansion problems?

1
  • Welcome to TeX.SX! A tip: You can use backticks ` to mark your inline code as I did in my edit.
    – user31729
    Commented Jul 20, 2014 at 12:50

1 Answer 1

13

First of all, after

\newcommand{\isempty}{\@empty}

the test

\ifx\isempty\@empty

will return false, because

  1. both \isempty and \@empty are macros, but
  2. they differ in their \long status.

However, also \newcommand*{\isempty}{\@empty} would make the test fail, because

  1. both \isempty and \@empty are macros, with the same \long status (both aren't \long), but
  2. they differ in their first level expansion, which is \@empty for \isempty and nothing for \@empty.

This assumes, of course, that your code is preceded by \makeatletter.

Why does \ifthenelse{\equal{\isempty}{\@empty} follow the true branch? Because the test does full expansion of the arguments of \equal. In both arguments the full expansion is empty. From the package documentation:

The ⟨string⟩s tested by \equal may be any sequence of commands that expand to a list of tokens. If these expansions are equal, then the proposition is true.

Basically, \ifx tests if the two tokens following it would give the same result when \meaning is applied to them. In the case of

\makeatletter
\newcommand{\isempty}{\@empty}

doing \meaning\isempty would print

\long macro:->\@empty

while \meaning\@empty would print

macro:->

so you see they're different as far as \ifx is concerned.


If you don't have \makeatletter before your code, the situation is a bit more complicated:

  1. the full expansion of \@empty, which is six tokens long, is

    \spacefactor \@m empty
    
  2. since \isempty first expands to \@empty, the \ifthenelse test will follow the true branch anyway;

  3. The \ifx test will compare \isempty with \@, which returns false, so empty will disappear along with the true text and the false branch will be followed.

2
  • Ah, I see. Many thanks! Is there any way to make such a test go "yes" using \ifx?
    – Mike
    Commented Jul 20, 2014 at 14:22
  • 1
    @Mike \let\isempty\@empty
    – egreg
    Commented Jul 20, 2014 at 14:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .