How \if is handled?

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.


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'.