Errors when using conditionals in document class optional argument

I have encountered a strange interaction between the optional parameters on \documentclass and \if statements. For some reason, the code compiles if there is an \else statement, even if it has no content:

\newif\ifdraftversion \draftversionfalse
\newif\iffullversion  \fullversionfalse

\documentclass[
\iffullversion  twoside,  \fi %works if the \fi here are
\ifdraftversion draft,    \fi % \else\fi instead
11pt
]{article}

\begin{document}
This is a MWE, although it generates an extra warning that would
disappear if I added substantially more content to the document
\end{document}


While this work-around is not particularly onerous, I have not been able to isolate the actual bug involved, or work out what I have misunderstood. Is there some reason why my intuition is leading me to use invalid syntax, and if so where/what/why?

• You should first ask whether this is supported syntax. No, it isn't. – egreg Jan 26 '17 at 13:55
• Thanks, that's what I was trying to get at with "or work out what I have misunderstood". I will update that sentence to be more clear, although following meta.tex.stackexchange.com/questions/3871/… I don't think I should change the title – figlesquidge Jan 26 '17 at 13:56
• – Werner Jan 26 '17 at 15:33

The \documentclass command does some bookkeeping, then calls

\@fileswithoptions\@clsextension


At this point the options and the argument haven't yet been looked at. The macro \@fileswithoptions absorbs its argument and then looks whether [ follows. After this decision, it executes

\@fileswith@ptions\@clsextension[<options>]{article}


which looks for a further optional argument; in the end we arrive at

\@fileswith@pti@ns\@clsextension[<options>]{article}[]


because you don't specify the trailing optional argument. This macro does

\xdef\@classoptionslist{\zap@space<options> \@empty}


so we should ask what happens if we do it with your options. After tokenization, we get

\zap@space \iffullversion twoside, \fi\ifdraftversion draft, \fi 11pt \@empty


The definition of \zap@space is

% latex.ltx, line 7764:
\def\zap@space#1 #2{%
#1%
\ifx#2\@empty\else\expandafter\zap@space\fi
#2}


For the first call, #1 is empty, so we get

\zap@space\iffullversion twoside, \fi\ifdraftversion draft, \fi 11pt \@empty


This leaves \iffulversion twoside, in the input stream and then does

\ifx\fi\ifdraftversion draft, \fi 11pt \@empty


Can you see what goes wrong? The conditional compares \fi with \ifdraftversion and removes them.

If you use \else\fi, then the comparison is between these two; you could use \relax\fi or \whateverevenundefined\fi.

At this point the unbalanced \fi is clear. In your application the error is discovered later, but this should be enough to explain that conditionals in the class options are to be avoided.

This works, by the way:

\newif\ifdraftversion \draftversionfalse
\newif\iffullversion  \fullversionfalse
\def\safetybelt{\empty}

\documentclass[%
\safetybelt\iffullversion  twoside,\fi
\safetybelt\ifdraftversion draft,\fi
11pt
]{article}

• I can indeed. It appears from what you've said that I would be fine building the parameter string within an initial \edef then chucking that down the parameter string. – figlesquidge Jan 26 '17 at 14:25
• @figlesquidge Yes, that's a more viable option – egreg Jan 26 '17 at 14:26

The "workaround" using \else\fi only seems to work. Your options are split on the commas, so you have the options \iffullversion twoside, \fi\ifdraftversion draft, and \fi 11pt.

The following code seems to work as expected (only verified by experiment):

\documentclass[
\iffullversion  twoside\fi, %works if the \fi here are
11pt
]{article}

• Interestingly (or so I think) your version doesn't work on my compiler (pdfTex 3.1415926-2.5-1.40.14). Thanks for answering my core question. I would be interested in a more involved answer or link to trusted source that outlined why this is not correct if you know of one? – figlesquidge Jan 26 '17 at 14:11
• @figlesquidge The trusted source is latex.ltx or latex.dtx, if you want to know precisely why it fails, or why some version works in certain situations. As egreg mentioned, your extension is not documented and not officially supported, so you can just try (and must expect that if fails any time). – gernot Jan 26 '17 at 14:20