Having the full conditional in the argument to \ifnot
is essential for the macro to work, or it cannot appear in another conditional, because TeX keeps track of \if...
, \else
and \fi
in skipped text.
Assuming the conditional \iftobe
is defined, your macro should work like
\ifnot{tobe}Not to be\else To be\fi
Now let's try
\iftrue
\ifnot{tobe}Not to be\else To be\fi
\fi
Instead of \iftrue
think to any other test, for instance \ifdim\maxdimen>0pt
, that returns true. This gives no problem, because the test is removed and \ifnot
is expanded, resurrecting the \iftobe
which will match the first \fi
.
Now consider
\iffalse
\ifnot{tobe}Not to be\else To be\fi
\fi
The test is false, so everything up to and including the matching \else
(or \fi
) is skipped. Well, there is \else
, so To be\fi\fi
remains in the input stream. Do you see the problem? There's one unmatched \fi
.
Giving to a macro a name that starts with \if
doesn't make it a conditional. Only control sequences that are \let
to a primitive conditional count. So TeX doesn't consider \ifnot
in the skipped text to be matched by \else
or \fi
.
You have to use a real conditional:
\newif\iftobe
\def\NOT#1{%
TT\fi
\csname if#1\endcsname\else
\expandafter\expandafter\fi
\iffalse\iftrue\fi
}
\tobetrue
\if\NOT{tobe}Not to be\else To be\fi
\tobefalse
\if\NOT{tobe}Not to be\else To be\fi
\bye
As an exercise, try
\iffalse\if\NOT{tobe}Not to be\else To be\fi\fi
and see that no error is raised.
The result is the same as
\newif\iftobe
\def\ifnot#1{#1\else
\expandafter\expandafter\fi
\iffalse\iftrue\fi
}
\tobetrue
\ifnot{\iftobe}Not to be\else To be\fi
\tobefalse
\ifnot{\iftobe}Not to be\else To be\fi
\bye
Of course, David Kastrup's macro is much more powerful, because you can use any conditional in the argument, for instance
\ifnot{\ifdim\maxdimen>0pt}TRUE\else FALSE\fi
will print FALSE.
Of course, with e-TeX it's easier:
\unless\ifdim\maxdimen>0pt TRUE\else FALSE\fi
would do the same.
An implementation that lifts the restrictions, but is simply useless, in my opinion. The trick is to make \tobe
equivalent to \iffalse
, so it will count when \ifnot\tobe
constructions are in the skipped text of a conditional. Of course, using \tobe
in the wild is not recommended. ;-)
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \newifnegatable #1
{
\exp_args:Nc \newif { if \cs_to_str:N #1 }
\cs_set_eq:Nc #1 { if_false: }
}
\cs_new:Npn \ifnot #1
{
\use:c { if \cs_to_str:N #1 }
\else:
\exp_after:wN \exp_after:wN \fi:
\if_false: \if_true: \fi:
}
\ExplSyntaxOff
\newifnegatable\tobe
\begin{document}
\tobetrue
\ifnot\tobe Not to be\else To be\fi
\iftrue\ifnot\tobe Not to be\else To be\fi\fi
\iffalse\ifnot\tobe Not to be\else To be\fi\fi
\tobefalse
\ifnot\tobe Not to be\else To be\fi
\iftrue\ifnot\tobe Not to be\else To be\fi\fi
\iffalse\ifnot\tobe Not to be\else To be\fi\fi
\end{document}
A perhaps more useful implementation (but \unless
is much easier anyway):
\documentclass{article}
\usepackage{etoolbox}
\newcommand{\newdoubleboolean}[1]{%
\newbool{#1}\newbool{not#1}%
\csappto{#1true}{\setbool{not#1}{false}}%
\csappto{#1false}{\setbool{not#1}{true}}%
\setbool{#1}{false}%
}
\newdoubleboolean{tobe}
\begin{document}
\tobetrue
\ifnottobe Not to be\else To be\fi
\iftobe To be\else Not to be\fi
\tobefalse
\ifnottobe Not to be\else To be\fi
\iftobe To be\else Not to be\fi
\end{document}
\unless
, right?\unless\if@I@miss@something
but\unless\@I@miss@something{would also be a nice approximation}
\ifnot
macro is designed to be used with an\if
the article you reference has an example\ifnot\iftrue
The usage\if@not\@to@be@
isn't the intended usage and\@to@be@
hasn't been defined, so it's not clear what you expect it to do\newif
(e.g., named\newifnot
) so, instead of creating the macros\iftobe
,\iftobetrue
and\iftobefalse
it would create also\ifnottobe
? I think it would be easier. And may be even appending the code to\newif
itself.