# Strange errors while writing a package

This short document:

\documentclass[a4paper]{report}
\usepackage{gnu}

\begin{document}
\end{document}


with the following package:

%!TEX encoding = UTF-8 Unicode
\def\fileversion{2.7}
\def\filedate{%
Tue 2014-07-22
}
\NeedsTeXFormat{LaTeX2e}[1996/06/01]
\typeout{Package 'mworx' (\filedate).}
\ProvidesPackage{gnu}

\RequirePackage{kvoptions}

\SetupKeyvalOptions{family=mworx,prefix=mw@,setkeys=\setkeys}

\newif\if@grave\@gravefalse

\DeclareBoolOption[true]{greek}
\DeclareVoidOption{ifgrave}{\@gravetrue}
\DeclareBoolOption[true]{save}
\DeclareBoolOption[false]{inpenc}
\DeclareBoolOption[false]{pack}
\DeclareBoolOption[true]{rootsyst}
\DeclareBoolOption[true]{loop}
\DeclareBoolOption[true]{fnsect}
\DeclareBoolOption[false]{fonts}
\DeclareBoolOption[false]{ptmx}
\DeclareBoolOption[true]{bb}
\DeclareBoolOption[true]{misc}
\DeclareBoolOption[true]{lengths}
\DeclareBoolOption[true]{dps}
\DeclareBoolOption[true]{xtras}
\DeclareBoolOption[true]{thm}
\DeclareBoolOption[true]{block}
\DeclareBoolOption[true]{mathdel}
\DeclareBoolOption[true]{mwmath}
\DeclareBoolOption[true]{oper}
\DeclareBoolOption[true]{mathsymb}
\ProcessKeyvalOptions*\relax

%Option "fonts"
\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright\enginerightfalse%Define new if to check if luatex or xetex are being used. To avoid typing the xetex/luatex commands twice.
\setmathrm{Times New Roman}
\setmathsf{Times New Roman}
\setmathtt{Times New Roman}
\setboldmathrm[BoldFont={Optima ExtraBlack}]{Optima Bold}
\defaultfontfeatures{Mapping=tex-text}
\setromanfont{Times New Roman}
\setsansfont{Times New Roman}
\setmonofont{Helvetica}
\newfontfamily{\vrb}{Helvetica}
\newfontfamily{\mapu}{Arial Unicode MS}
\newfontfamily{\Ar}{Geeza Pro}
\newfontfamily{\Chs}{STSong}
\newfontfamily{\Cht}{PMingLiU}
\newfontfamily{\Ja}{MS Mincho}
\newfontfamily{\Ru}{Times New Roman}
\newfontfamily{\Gr}{Times New Roman}
\newfontfamily{\He}{Times New Roman}
\newfontfamily{\Ko}{Batang}
\newfontfamily{\Ind}{Devanagari MT}
\newfontfamily{\Mal}{Malayalam MN}
\newfontfamily{\Sinh}{Free Sans}
\newfontfamily{\Thai}{Free Serif}
\newcommand{\€}{\Gr{ }}
\else
{}
\fi
%More commands that are OK in any engine I know of.
\newcommand{\mbold}{\mathbf}
\newcommand{\tbold}{\textbf}
\newcommand{\ital}{\textit}
\newcommand{\CAPS}{\textsc}
\newcommand{\slant}{\textsl}
\newcommand{\bemph}[1]{\tbold{\emph{#1}}}
\newcommand{\mrm}{\mathrm}
\fi

%Option "misc"
\ifmw@misc
%A few unclassifiable shortcuts.
\RequirePackage{color,graphicx,xparse}
\newcommand{\tick}{\checkmark}
\newcommand{\crux}{\dagger}
\newcommand{\dcrux}{\ddagger}
\newcommand{\hs}{\heartsuit}
\newcommand{\ds}{\diamondsuit}
\newcommand{\cs}{\clubsuit}
\newcommand{\tcrux}{$\dagger$}
\newcommand{\tdcrux}{$\ddagger$}
\newcommand{\ths}{$\heartsuit$}
\newcommand{\tds}{$\diamondsuit$}
\newcommand{\tcs}{$\clubsuit$}
\newcommand{\tss}{$\spadesuit$}
\newcommand{\bs}{\backslash}
\newcommand{\tbs}{$\bs$}
\newcommand{\bk}{\Gr{ }}
\NewDocumentCommand{O{1}O{1}}
{\scalebox{#1}[#2]{\color{white}a}}
\fi

\endinput


generates error Extra \fi on line 83 (right after \newcommand{\mrm}{\mathrm}. If I add:

\ifxetex
\enginerighttrue
\else
\ifluatex
\enginerighttrue
\else
{}
\fi
\fi


before \ifengineright, the error turns to Undefined control sequence. l.56 \ifengineright.

What is happening here?

• What's the purpose of \else{}? You shouldn't have \newif inside a conditional. – egreg Jul 25 '14 at 14:12
• Maybe none. Maybe it's just aesthetic. I mean, an \if with an \else looks better than one without, to me at least. Could that cause problems? – MickG Jul 25 '14 at 14:14
• Forget aesthetics in this case. – egreg Jul 25 '14 at 14:15

Where's the problem? Here's the analysis.

You have

\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright\enginerightfalse%Define new if to check if luatex or xetex are being used. To avoid typing the xetex/luatex commands twice.
\setmathrm{Times New Roman}
\setmathsf{Times New Roman}
% several other lines
\else
{}
\fi
%More commands that are OK in any engine I know of.
\newcommand{\mbold}{\mathbf}
\newcommand{\tbold}{\textbf}
\newcommand{\ital}{\textit}
\newcommand{\CAPS}{\textsc}
\newcommand{\slant}{\textsl}
\newcommand{\bemph}[1]{\tbold{\emph{#1}}}
\newcommand{\mrm}{\mathrm}
\fi


When \ifmw@fonts returns false, the “true code” is not executed, so \ifengineright is not defined and it is not regarded as a conditional. Therefore the first \else is assumed to end the “true code” for \ifmw@fonts and the “false code” will just contain {}.

If \ifmw@fonts returns true, TeX defines \ifengineright. and everything will go well.

Let's see a trimmed down example:

\newif\ifOUTER % \OUTERfalse is implicit

%\OUTERtrue

\ifOUTER
\newif\ifINNER % \INNERfalse is implicit
\ifINNER
\message{We're here}
\else
{}
\fi
\else
\message{Outer}
\fi


The error message are

! Extra \else.
l.12 \else

?
Outer
! Extra \fi.
l.14 \fi

?


When \OUTERtrue is uncommented, we get no error.

What happens is easy to explain: when a conditional turns out to be true, TeX simply removes it and the tokens that have been consumed for determining the boolean value, leaving to \else the job of removing the “false text”.

But when the conditional returns false all tokens up to and including the matching \else (or \fi, if no \else follows) are removed and not interpreted in any way, except that conditional inside them are matched with their corresponding \fi. However, \ifengineright is not a conditional, just an undefined token, in your code.

How does TeX determine a token is a conditional? Any primitive conditional is of course recognized and in addition all tokens \let to a primitive conditional. Indeed \enginerighttrue and \enginerightfalse execute \let\ifengineright\iftrue and \let\ifengineright\iffalse respectively. Nothing else is a conditional. Tokens \let to \else or \fi are recognized similarly for ending (branches of) conditionals.

The moral is “never define a new conditional inside a conditional”. Well, it's possible to do it, but not in this way.

By the way, \else {} \fi for an empty false text is not good programming: conditionals are fully expandable constructions, don't add unexpandable tokens unless you need to.

don't do this:

\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright


If you allocate a new if in a conditional section the \ifengineright might or might not be defined but the \fi is always a fi so you have unmatched fi in the undefined case.

• I took the lines from \RequirePackage{ifxetex,ifluatex} to just before \ifengineright, and moved them to before %Option "fonts". Now the error is Missing \begin{document} on line 120 (the last \fi). Why does that happen? – MickG Jul 25 '14 at 14:20
• Looks like the problem lies in that \NewDocumentCommand, as removing it removes the problem. But why? What's wrong with it? – MickG Jul 25 '14 at 14:26
• @MickG you haven't given it a command name to define!!!! – David Carlisle Jul 25 '14 at 14:27
• OK sorry I must be dizzy or something, I gave no name to that command. The error isn't helpful though. It should be «you stupid, give a name to that Document Command!» or the likes :). – MickG Jul 25 '14 at 14:28
• @MickG it's a macro expansion language, helpful error messages are hard. actually what happens is that each of the arguments gets interpreted in randomly incorrect ways and at some point in the middle of the definition of newdocument command the O in your argument specifier wasn't used for anything so fell through and tried to typeset an O before \begin{document} so you get the standard error about text before \begin{document} – David Carlisle Jul 25 '14 at 14:31