In the following example \def\a... fails if \ifabc is false and \myif is not initialized before \def\a.... In contrast, if \ifabc is true, \myif may be initialized before or after \def\a....

It is not clear to me why it does not fail when \ifabc is true and \myif is not initialized before \def\a.

\newif\ifabc
\abctrue % \abcfalse

%\let\myif=\iftrue

\ifabc
  \def\a#1#2{\myif#1\else#2\fi}
\fi

%\let\myif\iftrue

\ifabc
  \a{hello}{world}
\fi

\end
up vote 6 down vote accepted

This is a supplement to cfr's answer.

The TeX Book mentions the following in Chapter 20 Definitions (also called Macros) (p 210)

Notice that all of the control sequences for conditionals begin with \if..., and they all have a matching \fi. This convention - that \if... pairs up with \fi - makes it easier to see the nesting of conditionals within your program. The nesting of \if...\fi is independent of the nesting of {...}; thus, you can begin or end a group in the middle of a conditional, and you can begin or end a conditional in the middle of a group. Extensive experience with macros has shown that such independence is important in applications; but it can also lead to confusion if you aren’t careful.

Hmmm... one should be careful. :) Note that you have a form of nested \if...\fi as well as grouping {...}.

Also (p 213):

When an \if... is expanded, TeX reads ahead as far as necessary to determine whether the condition is true or false; and if false, it skips ahead (keeping track of \if...\fi nesting) until finding the \else, \or, or \fi that ends the skipped text. Similarly, when \else, \or, or \fi is expanded, TeX reads to the end of any text that ought to be skipped.

With the above information, we find that under \abcfalse, TeX "skips ahead ... until finding the \else ... that ends the skipped text", disregarding any grouping. As such, the expansion ends with evaluating #2 - a macro parameter - in vertical mode.

We can also use tracing (somewhat) what is is going on:

 1: \documentclass{article}
 2: 
 3: \begin{document}
 4: 
 5: \newif\ifabc% Default is \abcfalse
 6: 
 7: %\let\myif=\iftrue
 8: 
 9: \tracingifs1
10: \ifabc
11:   \def\a#1#2{\myif#1\else#2\fi}
12: \fi
13: 
14: %\let\myif\iftrue
15: 
16: \ifabc
17:   \a{hello}{world}
18: \fi
19: 
20: test
21: 
22: \end{document}

The tracing reveals \else was found (still in vertical mode) as part of the \if... statement on line 10:

{vertical mode: \iffalse: (level 1) entered on line 10}
{\else: \iffalse (level 1) entered on line 10}

! You can't use `macro parameter character #' in vertical mode.
l.11   \def\a#1#2{\myif#1\else#
                               2\fi}
Sorry, but I'm not programmed to handle this case;
I'll just pretend that you didn't ask for it.
If you're in the wrong mode, you might be able to
return to the right one by typing `I}' or `I$' or `I\par'.

I think ...

... that when \abctrue, the condition holds, so \def goes through. Hence, TeX doesn't try to execute the content of the \def until the macro is actually used.

However, when \abcfalse, it has to read through the content of \def looking for an \else. Since \myif is not known as a conditional, it doesn't realise that the \else is nested. Hence, it reads the stuff after the \else as the thing it is meant to execute, given that \abcfalse. And this fails because #2 can't be used here.

Try

\def\a#1#2{\myif#1\else\show\super#2\fi}% but not for real - never \def a single letter macro name unless you are really, really sure you want to overwrite anything it alreay means.

to see that this is what is happening:

> \super=undefined.
l.153   \def\a#1#2{\myif#1\else\show\super
                                          #2\fi}
? 
! You can't use `macro parameter character #' in vertical mode.
l.153   \def\a#1#2{\myif#1\else\show\super#
                                           2\fi}

In contrast, if you had \show\super before the \else and set \abctrue, it would never be executed unless you actually used the defined macro.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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