Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

A few days ago I tried to point out to Will Robertson one of the pitfalls of eTeX’s \ifcsname and \ifdefined but he didn’t seem to get the message. Please am I right in saying that the following beckons us to be cautious when using\ifcsname and \ifdefined, since they return 'true' when a command is made \relax? Tests like etoolbox's \ifdef and \ifcsdef should be preferred when the aim is to test if a command is equivalent to \undefined.

With the hope of later doing, e.g., \expandafter<cmd>\x, I defined

\edef\x{\unexpanded\expandafter{\csname test@\romannumeral\currentgrouplevel\endcsname}}

After some intervening code, I then did

\ifcsname test@\romannumeral\currentgrouplevel\endcsname
  \def\y{Yes}
\else
  \def\y{No}
\fi
\show\y

On the face of it, there was no apparent relation between defining \x and the later test. I first wondered where test@\romannumeral\currentgrouplevel was defined. It took me some time to locate the problem.

share|improve this question
6  
Two rather separate issues here: could you post the \edef\x{\ifnum0=0\else\fi} separately, and perhaps give this one a clearer name? –  Joseph Wright May 26 '12 at 8:56
1  
I agree with @Joseph on both accounts. Also, the second question is quite related to your existing question How to vanish \relax inserted by TeX itself. TeX inserts an implicit \relax because it finds \else in number reading mode which needs to be terminated then. –  Martin Scharrer May 26 '12 at 9:10
    
@MartinScharrer: Thank you for the reference. The question I should actually be asking is why is it that with \edef\x{\ifnum0=0\else\fi} being \relax and \def\y{\relax}, we see that \ifx\x\y is false? Are there two types of \relax? –  Ahmed Musa May 26 '12 at 10:35
1  
@AhmedMusa I can transfer the second part of my answer, if you make a new question. –  egreg May 26 '12 at 10:47
2  
It beckons us to be careful with \csname ... \endcsname because that does define the cs (which is precisely why the eTeX developers added the new primitives to allow for an expandable test that doesn't define the cs). So perhaps you should reword the start of your question. –  Frank Mittelbach May 26 '12 at 15:12
show 1 more comment

3 Answers

up vote 9 down vote accepted

It's not misleading because it follows the precisely laid out rules.

  1. When \csname is expanded, TeX looks for the matching \endcsname with expansion; then TeX forms a control sequence token from the character tokens (irrespective of category code) it has found or issues an error if some non character token is discovered.

  2. After the formation of the token, TeX looks up in its memory to find if that token has a meaning. If it hasn't, that token is made equivalent to \relax with a local assignment.

  3. \edef expands the tokens it finds between the braces that delimit the replacement text before storing the resulting <balanced text> as the replacement text.

Thus your \edef\x{\csname totallyundefined\endcsname} is equivalent to

\let\totallyundefined\relax
\def\x{\totallyundefined}

On the contrary, the \ifdefined and \ifcsname tests (by precise choice of e-TeX's developers) never perform the assignment to \relax of an undefined token.

The \relax assignment is performed in many other cases as a precaution against premature expansions. Two cases mentioned in the TeXbook are

\chardef\cs=10\cs
\font\cs=name\cs

where \cs is temporarily made equivalent to \relax in order to stop expansion when the assignment is performed. In such cases it's really temporary, as \cs will immediately be assigned a new meaning; in the case of \csname it isn't. Where's the problem? If \cs had a previous definition, without the temporary assignment to \relax, TeX would expand \cs searching for a number in the first case or the end of the file name in the second. Even worse, if \cs was undefined, an error would be raised, because TeX hasn't yet assigned to \cs the new meaning. Of course, using such a syntax is discouraged.

It may be unfortunate that e-TeX uses \ifcsname...\endcsname with the same rules of \csname...\endcsname for the formation of the token to be examined, but with the fundamental difference that the equivalence to \relax is not performed, but that's what it is.


In the case you're presenting, that is

\edef\x{\unexpanded\expandafter{\csname test@\romannumeral\currentgrouplevel\endcsname}}

you might do it indirectly:

\edef\x{\noexpand\csname @test\romannumeral\currentgrouplevel\endcsname}

so that the \csname won't be executed. Of course \x would need two expansions steps:

\expandafter\expandafter\expandafter\cs\x
share|improve this answer
    
\endcsname is unexpandable, so you don't need that second \noexpand in your last example. –  Bruno Le Floch May 26 '12 at 22:25
    
@BrunoLeFloch Thanks. –  egreg May 26 '12 at 22:26
    
@egreg: \chardef\cs=10\cs gives {\char"A}\everypar->\@nodocument outside \document. This syntax should be qualified. –  Ahmed Musa May 27 '12 at 0:53
    
@AhmedMusa This is a Plain TeX example. Of course you get an error if use that in the preamble of a LaTeX document, because you're trying to typeset a character. –  egreg May 27 '12 at 8:29
add comment

Both \ifcsname and \ifdefined test if the control sequence is defined at all, this includes control sequences which are equal to \relax. Earlier tests use \expandafter\ifx\csname abc\endcsname\relax which uses the feature of \csname to define undefined control sequences automatically to be equal to relax. You are right that mixing these two ways to test is dangerous, because any \ifx\csname test or other \csname on the same name will change the outcome of the other two tests on the same control sequence, because it is now defined equal to \relax. Both \ifcsname and \ifdefined intensionally do not define the control sequence to \relax and should actually be preferred over \ifx\csname, but you might only want them to use with control sequences your package etc. defines itself where no other code tested it using a different test.

BTW: You can use grouping like: \begingroup\expandafter\ifx\csname abc\endcsname\relax\endgroup ..\else\endgroup .. \fi, to keep the \csname definition local, but the LaTeX core macro \@ifundefined doesn't do that.

share|improve this answer
1  
The problem with Heiko-style \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname x\endcsname ... is that it isn't expandable. –  Ahmed Musa May 26 '12 at 10:43
    
@AhmedMusa: Yes, I know. I was thinking mentioning that, but the question didn't mentioned expandability so I didn't. –  Martin Scharrer May 26 '12 at 10:44
add comment

Not sure if the second part of the question will be migrated but here is an explanation in any case.

The expansion of \ifnum...\fi is empty if the test is false, \relax otherwise, thus the meaning of

   `\edef\x{\ifnum0=0\fi}`

is

   `macro:->\relax`

Try this test for fun:

    {\def\relax{0}\xdef\foo{\ifnum0=0\fi}}

This puts \relax in \foo. Although tricky, this token is not the same token as the one that follows the \def, since otherwise 0\fi would expand to 0\relax\fi then 00\fi, then 00\relax\fi without end (and without overflow).

This behaviour is not an oddity, but a mind boggling fact!

share|improve this answer
    
Sorry, but the explanation is incorrect: with \edef\x{\ifnum0=0 \fi} the expansion of \x is empty. –  egreg May 26 '12 at 9:46
    
@egreg Not on my computer! Try \edef\x{\ifnum0=0\fi} \tt \meaning\x \bye –  Yiannis Lazarides May 26 '12 at 9:54
    
You didn't notice the space before \fi. –  egreg May 26 '12 at 9:54
    
@egreg True if you leave a space or an A for example but I don't see why you say the explanation is incorrect. –  Yiannis Lazarides May 26 '12 at 10:04
    
The correct explanation is "unfinished conditional" and "frozen \relax" that I learnt from David Kastrup. –  egreg May 26 '12 at 10:10
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.