# \newif conditional causing problem in \typeout or \edef

The following code produces result as expected, i.e.,

False True

on the typeset document.

\documentclass{minimal}

\newif\iftest

\newcommand{\test}[2]{
\iftest
#1
\else
#2
\fi
}
\newcommand{\ex}{\test{True}{False}\testtrue\test{True}{False}}

\begin{document}
\ex
\end{document}


However, if I wrap \ex with \typeout, or try to \edef\ex instead of \newcommand I get:

! Incomplete \iffalse; all text was ignored after line...

-
Welcome to TeX.sx! You mean \typeout and not \typeset, right? –  Werner Nov 22 '11 at 19:12
Please don't use the minimal class for minimal working examples (MWE). Despite the name it is not intended for that and can cause problems, because it does not define everything a real class does. Also a MWE should actually show what is not working, i.e. add the code which causes the trouble. –  Martin Scharrer Nov 22 '11 at 19:23
Martin: the above example uses nothing from a documentclass so minimal is a good choice here, or at least not a bad one ... –  Herbert Nov 22 '11 at 19:40
@Herbert: Yes, well article doesn't do any harm either. It is better to be consistent and because the OP is new here I mentioned it, so that he doesn't start any bad habits. –  Martin Scharrer Nov 22 '11 at 19:54
If you want to implement a "once only warning", put \global\testtrue outside the \typeout. –  egreg Nov 23 '11 at 22:46

The problem here is that \testtrue is not expandable and not protected and therefore fragile. It is defined as \let\iftrue\iftrue. In an expandable context like \edef or \typeout the \let assignment is ignored, and both if-switches are expanded. Because there is only one \fi (which is taken as part of \iftrue) the compiler complains about the missing \fi.

You can use \test{<true>}{<false>} in this context, but not \testtrue or \testfalse. So you would need to do the following:

\typeset{\test{True}{False}}
\testtrue
\typeset{\test{True}{False}}


I like to give you one more advice. I would define the \test macro as follows:

\makeatletter
\newcommand{\test}{%
\iftest
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\makeatother


This way the if-statement is fully processed before one of the two arguments is processed. This avoid some issues with can arise when code is used inside and if-switch. For example defining a new if-switch with \newif and using it inside such an argument will break, if that argument is to be skipped. The \@firstoftwo and \@secondoftwo macros simply take two arguments and expand to either the first or the second. The \expandafter expands (i.e. removes, in this case) the \else or \fi first. Also note the % after the { which is required to avoid a space being added there by the line break.

-
So I guess I've bumped in the moving argument problem. I've done some reading and as far as I understand, one can't simply jump out expansion, execute unexpandable token, and then continue expanding? –  JKS Nov 23 '11 at 21:28
@JKS: No, you can't jump out. –  Martin Scharrer Nov 23 '11 at 21:42
@JKS: You need to do any non-expandable things, like assignments, outside the expanding macro. Not sure what you mean with expandsion-only context, but \edef\foo{<content>} expands it content fully. Non-expandable macros will stay the same. –  Martin Scharrer Nov 24 '11 at 16:23
I meant on total expansion, like in \edef, \write, \typeout, ... –  JKS Nov 24 '11 at 19:49