Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Today, I decided to migrate from using TeX [$..$] to LaTeX [\(..\)] delimiters for inline maths, and, as usual, fell off the cliff of my somewhat precarious understanding of TeXian gastroenterology, in the middle of an algpseudocode environment.

Here's my MWE:

\documentclass{article}
\usepackage{algpseudocode}
\begin{document}
\begin{algorithmic}[1]
\Procedure{Trigger Dispatching Scheduler}{}
\State \Call{MqOpen}{$\aleph$}
\State \Call{MqOpen}{\(\aleph\)\relax}
%\State \Call{MqOpen}{\(\aleph\)} % <== This one fails
\EndProcedure
\end{algorithmic}
\end{document}

Uncommenting the %-line causes it to fail (PdfLaTeX and XeLaTeX) with:

! Argument of \) has an extra }.
<inserted text> 
                \par 
l.14 \State \Call{MqOpen}{\(\aleph\)}
                                      % <== This one fails

What, if anything, am I doing wrong? If anyone could explain in fairly simple terms what's going on here, I'd be most grateful.

share|improve this question
    
Does this have anything to do with the word 'fragile' (which precisely describes my understanding of these things) –  Brent.Longborough Jun 9 '12 at 15:00
1  
I think so (based on Why is the ifthen package obsolete?) and algorithmicx(http://ctan.org/pkg/algorithmicx) uses [ifthen to condition on many levels. For example, using \State \Call{MqOpen}{\protect\(\aleph\protect\)} works. Not exactly sure why \relax makes it work though. –  Werner Jun 9 '12 at 15:03
add comment

1 Answer

up vote 6 down vote accepted

I give an answer below saying it's a bug in ifthen package, but I think I'm going to reclassify it as a feature.

In unmodified LaTeX2e \( \nd \) are fragile commands and as such they should be preceded by \protect if used in a moving argument (as the argument of \equal).

\ifthenelse{\equal{\protect\(a\protect\)}{\protect\(a\protect\)}}{\typeout Y}{\typeout N}

does work as intended.

If you load the fixltx2e package part of the core base distribution then \( and \) are made robust so you (and even I) might have expected that \protect is not necessary. However the due to the way \ifthenelse overloads the \( \) syntax to be a boolean logic parenthesis rather than math start, \( is made fragile again. The "fix" below locally gives \(\) robust definitions however due to the "interesting" expansion order implemented in ifthenelse This local redefinition applies to the entire predicate not just the arguments to \equal and so the "fix" is entirely wrong as it removes the ifthenelse definition of \(\) entirely.

Sorry (if you want to take away the green tick I'd understand:-) but unless sleeping on it gives me a better idea, or another contributor has a better idea, I think the only thing I can do is more clearly document in ifthen that if you use the ifthen syntax commands (\(\)\or\and\isodd etc inside an \equals test, then you need to \protect them.


Sorry it's a bug.

\ifthenelse uses delimiters \( and \) to brackets boolean expressions. These are not made safe in the strings used by ifthenelse \equal test. The following inserts a local definition to make things safer,

 \let\(\relax\let\)\relax

without this line you get the same error shown in your MWE.

\documentclass{article}
\usepackage{ifthen}

\makeatletter

\long\def\ifthenelse#1{%
  \toks@{#1}%
  \TE@repl\or\TE@or
  \TE@repl\and\TE@and
  \TE@repl\not\TE@neg
  \TE@repl\OR\TE@or
  \TE@repl\AND\TE@and
  \TE@repl\NOT\TE@neg
    \begingroup
        \let\protect\@unexpandable@protect
        \def\@setref##1##2##3{%
         \ifx##1\relax\z@\else\expandafter##2##1\fi}%
        \def\value##1{\the\csname c@##1\endcsname}%
        \let\equal\TE@equal \let\(\TE@lparen \let\)\TE@rparen
        \let\isodd\TE@odd \let\lengthtest\TE@length
        \let\isundefined\TE@undef
        \begingroup
          \let\@tempa\relax\let\@tempb\relax
          \let\(\relax\let\)\relax
          \xdef\@gtempa{\expandafter\TE@eval\the\toks@\TE@endeval}%
        \endgroup
        \@gtempa
        \expandafter\endgroup\ifTE@val
          \expandafter\@firstoftwo
        \else
          \expandafter\@secondoftwo
        \fi}

\makeatother


\ifthenelse{\equal{a}{a}}{\typeout Y}{\typeout N}
\ifthenelse{\equal{a}{b}}{\typeout Y}{\typeout N}
\ifthenelse{\equal{\(a\)}{\(a\)}}{\typeout Y}{\typeout N}
\ifthenelse{\equal{\(a\)}{\(b\)}}{\typeout Y}{\typeout N}


\stop


This produces

Y
N
Y
N
 )
No pages of output.

on the terminal showing the tests worked.

share|improve this answer
    
Thanks, David. What do you think is the best way of "implementing" this?: (a) make a patched local copy of ifthen.sty, or (b) put your code into a local fixifthen.sty and then \usepackage{fixifthen}? –  Brent.Longborough Jun 9 '12 at 21:14
    
actually I'm not sure that's quite the right fix (I may have broken the ifthen use of \( I need to make a couple of test cases. As it's clearly a bug I would just patch ifthen.sty locally (putting some note in the \ProvidesPackage line to note it is modified) that way the document doesn't need changing once the main distribution gets fixed. –  David Carlisle Jun 9 '12 at 22:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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