3

Please consider the following, non-working, example:

\documentclass{standalone}

\makeatletter
  \parindent\z@
  \@namedef{blafasel}{foo}
  \def\foo{foo}
  \def\bar{bar}
\makeatother

\begin{document}
1:
\expandafter\ifx\@nameuse{blafasel}\foo
  \message{true}
\else
  \message{false}
\fi    

2: 
\expandafter\ifx\@nameuse{blafasel}\bar
  \message{true}
\else
  \message{false}
\fi

\end{document}

How must I alter this code so that the output is "correct" (1: true\n2: false)? So far, I tried up to 9 \expandafter before \ifx, but none gave me the desired output. Why is that?

EDIT

Okay, my mistake was that @ wasn't a letter anymore... Using three \expandafters did the trick. Nonetheless i'd like to know what happens here. How does LaTeX expand @namedef and @nameuse resp.? Extending the example by the following code also gives weired results:

3: 
\expandafter\ifx\csname blafasel\endcsname\bar
  true
\else
  false
\fi

4: 
\expandafter\ifx\csname blafasel\endcsname\bar
  true
\else
  false
\fi
  • I'd use etoolbox's \ifcsequal{<csname one>}{<csname two>}{<true>}{<false>} – moewe Jan 24 at 11:37
  • Yea, thanks all, i noticed my mistake as soon as i clicked "submit"... I added a "follow up" to the question, see edit above. Using \(end)csname gave me twice "false" for some reason... – Lupino Jan 24 at 11:41
  • 2
    If you use \foo in 3, then you'll get true. You're getting false twice because you're doing the same test. – egreg Jan 24 at 11:43
  • @egreg and all: m( i'm so sorry – Lupino Jan 24 at 11:45
7

You're almost there. Two problems only.

First, \@nameuse contains an @ in the name, so you need to \makeatletter before using it.

Second, if you \show\@nameuse (after a \makeatletter, of course) you see:

> \@nameuse=macro:
#1->\csname #1\endcsname 

so one expansion of \@nameuse{foo} yields \csname blafasel\endcsname. The \csname...\endcsname requires another expansion to make \blafasel, which is what you want. So now you know you need two expansions of \@nameuse.

With

\expandafter\ifx\@nameuse{blafasel}\foo

you expand it once. To expand twice you need one more \expandafter before each token that precedes \@nameuse. That is, one \expandafter for the "old" \expandafter, and another for the \ifx:

\expandafter\expandafter\expandafter\ifx\@nameuse{blafasel}\foo

Now the code:

\documentclass{standalone}

\makeatletter
  \parindent\z@
  \@namedef{blafasel}{foo}
  \def\foo{foo}
  \def\bar{bar}
\makeatother

\begin{document}
1:
\makeatletter
\expandafter\expandafter\expandafter\ifx\@nameuse{blafasel}\foo
  \message{true}
\else
  \message{false}
\fi    

2:
\expandafter\expandafter\expandafter\ifx\@nameuse{blafasel}\bar
  \message{true}
\else
  \message{false}
\fi

\end{document}

prints true false somewhere in the terminal.

  • thank you, i'm going to accept the answer because it answers the OP. Unfortunately, in my "real" code, which is an xmltex project, this doesn't work. TeX complains about an Extra \else with this construction. – Lupino Jan 24 at 11:50
  • I found the difference: In my "real" code i used \relax instead of \foo or {foo}. This gives me "false" twice – Lupino Jan 24 at 11:56
  • @Lupino I'd need to see the code... The Extra \else shouldn't appear even if you replace \foo by \relax. \ifx compares the meaning of two tokens without expanding them previously, so \relax is valid. Of course the comparison will only be true if both tokens expand to \relax, for instance this code first yields foo is NOT relax because, obviously, \foo is not \relax, it only contains \relax in its definition. The second comparison yields foo is relax because you make \foo an exact copy of \relax. – Phelype Oleinik Jan 24 at 12:16
4

You need to expand two levels, so \expandafter\expandafter\expandafter, besides making @ a letter in order to avoid TeX compare the first two tokens in the expansion of \@ (precisely, \spacefactor and \@m).

A single \expandafter is sufficient with \expandafter\ifx\csname blafasel\endcsname\foo.

There are simpler ways to compare macros expanding to strings of characters, the simplest one being

\ifnum\pdfstrcmp{\@nameuse{blafadel}}{foo}=0
  true
\else
  false
\fi

that doesn't need to define \foo. Since \pdfstrcmp is available with different names in other engines, it's best to do

\usepackage{pdftexcmds}

and use \pdf@strcmp.

Much more powerful string comparison functions are available with expl3.

  • Thanks for the answer. Is that package bound to pdflatex? If so, i cant use it. Dvi output only... – Lupino Jan 24 at 12:02
  • @Lupino No, you can use expl3 with any of the major engines (pdfTeX, XeTeX, LuaTeX, (u)pTeX) and it doesn't depend on the format being used, so you can use with plain, LaTeX, ConTeXt or basically any other format. It won't work in Knuth's TeX though, because it requires ε-TeX extensions. – Phelype Oleinik Jan 24 at 12:20
  • Since we are using Texlive2017 this should be fine. I will have a look at it, maybe i find something useful in there. Thanks for the advice :) . – Lupino Jan 24 at 14:55

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.