11

How do I get the following MWE to work:

\documentclass{article}
\usepackage{xifthen}
\usepackage{lipsum}

\newboolean{bar}
\setboolean{bar}{true}
\def\foo{\parshape = 2
   \ifthenelse{\boolean{positionLeft}}{%
     0pt 0.5\textwidth%
   }{%
     0.5\textwidth 0.5\textwidth%
   }%
  0pt \textwidth
}

\begin{document}

\foo
\lipsum[1]

\end{document}

I believe it has something to do with the \ifthenelse not being expanded, but I never seem to get the hang of that (I really need to get the TeXbook any time soon)...

11

\ifthenelse does assignments, that aren't allowed for setting \parshape.

Use the conditional commands provided by etoolbox:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{lipsum}

\newtoggle{bar}
\toggletrue{bar}
\def\foo{\parshape = 2
   \iftoggle{bar}{%
     0pt 0.5\textwidth
   }{%
     0.5\textwidth 0.5\textwidth
   }%
  0pt \textwidth
}

\begin{document}

\foo
\lipsum[1]

\end{document}

If you insist with \ifthenelse, you have to provide the entire specification:

\def\foo{%
   \ifthenelse{\boolean{bar}}{%
     \parshape = 2
     0pt 0.5\textwidth%
     0pt \textwidth
   }{%
     \parshape = 2
     0.5\textwidth 0.5\textwidth%
     0pt \textwidth
   }%
}

When TeX sees a \parshape command, it expects to see a number n and, if n > 0, 2​n lengths. The rule about these “expectations” is that TeX expands macros until it finds what it's looking for. For instance, if one says

\def\baz{2} \def\bazz{0pt} \def\bazzz{\textwidth}
\parshape \baz \bazz .5\bazzz 0pt \bazzz

then TeX will expand everything and do exactly as if it were presented

\parshape 2 0pt .5\textwidth 0pr \textwidth

(note that \textwidth is unexpandable). Any unexpandable token will of course stop a search and two cases are possible:

  1. the unexpandable token is meaningful in this context (a number or a length parameter), or

  2. the unexpandable token is out of place.

The definition of \ifthenelse is found in ifthen.sty:

% ifthen.sty, line 70:
\long\def\ifthenelse#1{%
  \toks@{#1}%
  \TE@repl\or\TE@or
  [...]
}

and the first line is an assignment: the token register named \toks@ is assigned the argument to \ifthenelse. Since \toks@ is not expandable, we end up in the second case described above, whence the error message issued by TeX.

This doesn't happen with etoolbox's \iftoggle, because care has been taken in order that it's “fully expandable” without any assignment, except when there's some error related to the toggle (for instance the toggle's name is mistyped), when it doesn't matter because there would be an error anyway.

  • \iftoggle works perfectly! Could you please explain what "assignments" means in this context, and why that makes a difference in this case? – gablin Sep 1 '13 at 8:59
  • @gablin I hope the added explanation is what you were looking for. – egreg Sep 1 '13 at 9:43
  • Excellent explanation; most appreciated! Unfortunately I can only vote once. =) – gablin Sep 2 '13 at 6:34
11

You could use a simple \newif without packages:

\documentclass{article}
\usepackage[latin]{babel}
\usepackage{lipsum}

\newif\ifbar
\bartrue

\def\foo{\parshape = 2
   \ifbar%
     0pt 0.5\textwidth%
   \else
     0.5\textwidth 0.5\textwidth%
   \fi
  0pt \textwidth
}

\begin{document}

\foo
\lipsum[1]
\barfalse
\foo
\lipsum[1]

\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.