A more elegant version of the \ifnot macro

Possibly something like this? It preserves the OP's desired syntax \ifnot\tobe, while at the same time not demanding that \tobe be predefined. Additionally, for those who don't like using \tobe without defining it, it allows the alternate syntax \ifnot{tobe}, without any changes whatsoever.

\documentclass{article}
\makeatletter
% Following 3 lines thanks to Prof. Enrico Gregorio, from:
% http://tex.stackexchange.com/questions/42318/
% removing-a-backslash-from-a-character-sequence
\begingroup\lccode`\|=`\\
\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}}
\newcommand{\@macro@name}[1]{\expandafter\removebs\string#1}
%
\def\ifnot#1{%
  \edef\tmp{if\@macro@name{#1}}%
  \csname\tmp\endcsname\else
    \expandafter\expandafter\fi
    \iffalse\iftrue\fi}
\makeatother
\newif\iftobe
\begin{document}
  \tobetrue
  \ifnot\tobe Not to be! \else To be!\fi\par
  \tobefalse
  \ifnot\tobe Not to be! \else To be!\fi
\end{document}

enter image description here


Using e-TeX and assuming \escapechar is printable and not a space:

\documentclass{standalone}
\makeatletter
\newif\if@to@be@
\def\if@not#1{%
  \expandafter\unless\csname
    \expandafter\expandafter\expandafter i%
    \expandafter\expandafter\expandafter f%
      \expandafter\@gobble\string#1\endcsname
}
\begin{document}
  \@to@be@true
  \if@not\@to@be@ Not to be! \fi
  \@to@be@false
  \if@not\@to@be@ Not to be! \fi
\end{document}

(The restriction on \escapechar can be lifted if required: see \cs_to_str:N in expl3.)


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

enter image description here

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}

enter image description here

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}

enter image description here