# ampersand “&” causes if-else-fi to fail

I encountered a very strange problem today.

I want to fill tables with automatic generated data. Hence, I designed a macro, which takes four arguments (one being optional). Arguments No. 1 and 4 are allowed to be empty, therefore I put an \ifx#1\@empty test into my code.

This is my macro in the first version:

\newcommand{\admin}[4][]{%
#2&#3&
\def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
\def\@ldap{#1}\ifx\@ldap\@empty\relax
yes
\else
& no
\fi%
\\%
}


I was very surprised to find, that LaTeX didn't compile. This was the result:

! Extra \fi.
\\admin ...ldap @empty \relax yes \else & no \fi
\\
! Incomplete \ifx; all text was ignored after line 51.
< inserted text>
\fi

After two hours fiddling, I found out, that the ampersand causes all the trouble. This macro works without LaTeX throwing an error:

\newcommand{\admin}[4][]{%
#2&#3&
\def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
\def\@ldap{#1}\ifx\@ldap\@empty\relax
yes
\else
no
\fi%
\\%
}


The disadvantage is, that the word "No" is now standing in the wrong column. :-( My MWA (Minimal Work Around) is now as follows, but I'd like to know, what went wrong and how to avoid the additional if-clause I came up with.

\documentclass{article}

\makeatletter
%% This did not work due to the "&".  Removing the ampersand will get
%% the macro working, but than the word "No" from the ifclause will be
%% printed in the wrong column.
%   #2&#3&
%   \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
%   \def\@ldap{#1}\ifx\@ldap\@empty\relax
%     yes
%   %% The error starts here.  Comment out the next two lines, and the
%   %% error vanishes.  Remove the ampersand & and its also gone!
%   \else
%     & no
%   %% This would work
%   % \else
%   %   no
%   \fi%
%   \\%
% }

%% Now: this works, but you have to have an extra if-clause!
#2&#3&%
\def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
\def\@ldap{#1}\ifx\@ldap\@empty\relax
Yes
\fi
&
#2&#3&%
\def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
\def\@ldap{#1}\ifx\@ldap\@empty\relax
Yes
\fi
&
\ifx\@ldap\@empty\relax\else
No
\fi%
\\%
\def\@ldap{#1}\ifx\@ldap\@empty\relax\else
No
\fi%
\\%
}
\makeatother

\begin{document}
\begin{tabular}{@{}lllcc@{}}
\hline
\multicolumn{2}{@{}c}{Anwender}
& \multicolumn{1}{c}{RZ-ID}
& \multicolumn{2}{c@{}}{LDAP} \\
\multicolumn{1}{@{}c}{Vorname}
& \multicolumn{1}{c}{Nachname}
&
& \multicolumn{1}{c}{Yes}
& \multicolumn{1}{c@{}}{No} \\
\hline
\hline
\end{tabular}
\end{document}


PS.: This is a minimal example. In my real document, the macro is way more elaborative, as I added a lot more info to the second-last and last column. Therefore, a suggestion, to use \multicolumn{2}{c}{Yes} or \multicolumn{2}{c}{NO}, spanning the last two columns to avoid the ampersand, is no option to me.

• A conditional cannot straddle alignment cells. – egreg Dec 10 '19 at 15:37
• @egreg Thank you for your advice. – Jan Dec 10 '19 at 16:05

Note that in your actual MWA (I like that! :-D) you are getting

which probably isn't the intended result. The reason behind it is the same as the reason why your first solution fails: cells are groups, and your \def\@ldap is restricted to the fourth column. You should use \gdefinstead to have it working.

Personally I see no point in avoiding the double \if at all costs but this would be a possible way

\newcommand{\admin}[4][]{%
#2&#3&%
\def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi &
\def\@ldap{#1}%
\ifx\@ldap\@empty\relax % I prefer \if\relax\detokenize{#1}\relax
\def\@tempa{\textcolor{green}{\ding{51}}&}%
\else
\def\@tempa{&\textcolor{red}{\ding{55}}}%
\fi
\@tempa
\\
}


Basically, the \if just sets the definition of\@tempa, which is expanded only after the \if has been worked out.

• Very cool and helpful answer. – Jan Dec 10 '19 at 16:08

Conditionals cannot straddle alignment cells, but you can remove the conditional before issuing &; the technique uses \@firstoftwo and \@secondoftwo. See Why the \expandafter\@firstoftwo idiom?

\documentclass{article}

\makeatletter

#2&#3&%
\if\relax\detokenize{#4}\relax
./.%
\else
#4%
\fi&%
\if\relax\detokenize{#1}\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{Yes}{&No}%
\\%
}
\makeatother

\begin{document}
\begin{tabular}{@{}lllcc@{}}
\hline
\multicolumn{2}{@{}c}{Anwender}
& \multicolumn{1}{c}{RZ-ID}
& \multicolumn{2}{c@{}}{LDAP} \\
\multicolumn{1}{@{}c}{Vorname}
& \multicolumn{1}{c}{Nachname}
&
& \multicolumn{1}{c}{Yes}
& \multicolumn{1}{c@{}}{No} \\
\hline