4

I struggle with the syntax of the macros. Basically I want to check if I should use \section or the starred section \section* depending on the parameter.

\documentclass{article}

\newcommand\mySection[2]{
    \ifnum #2=1 
    \expandafter\expandafter\expandafter\section
    \else\section*
    \fi
    {#1}
}

\begin{document}
    test
\mySection{title}{1}
\mySection{title}{0}
    
\end{document}

The second command receives an error ! Extra \else. How to get the MWE working?

2
  • why do you use low-level tex instead of a test from etoolbox or expl3? – Ulrike Fischer Jan 15 at 16:38
  • I found a working solution with the given responses - for which I'm thankful. But the given answers raise additional questions. Therefore I opened another question tex.stackexchange.com/q/579233/48642. Just as a followup... – LeO Jan 17 at 16:51
4

You didn't count \expandafters well. Your test file should be:

\documentclass{article}

\newcommand\mySection[2]{
    \ifnum #2=1 
    \expandafter\section
    \else\expandafter\section\expandafter*%
    \fi
    {#1}
}

\begin{document}
    test
\mySection{title}{1}
\mySection{title}{0}

\end{document}

The general rule: the \expandafters chain must touch the \else in the first part of condition and the \fi in the second part.

3
  • Thx for the response and this works. I wasn't aware that I need to expand before the *. Your general rule means that I need to have the same no of \expandafter in each of the branches - right? – LeO Jan 15 at 17:15
  • 2
    @LeO No, you have one token in the first branch: \section, so you have to touch to the \else by one \expandafter. You have two tokens in the second branch: \section *. You have to touch the \fi by two \expandafters. In general: this chain must alternate \expandafter token \expandafter token etc. \expandafter token \fi. – wipet Jan 15 at 18:02
  • @LeO In the \if..-branch you need one \expandafter-chain "hitting" the token \else. In the \else..-branch you need one \expandafter-chain "hitting" the token \fi. The amount of \expandafter in the respective \expandafter-chain depends on how many tokens in the respective branch need to be " jumped over" for "reaching" the \else/the\fi. – Ulrich Diez Jan 15 at 20:15
4

Let's look at \if..\else..\fi-conditionals:

Expanding the \if... of an \if..\else..\fi while the \if..-condition is fulfilled yields evaluation and removal of the tokens that are needed for finding out whether the \if..-condition is fulfilled.

E.g., expanding the \ifnum of

\ifnum1=1 equal\else different\fi

yields: equal \else different\fi .

In further processing equal is carried out. After that \else is carried out/expanded.

The result of carrying out/expanding \else is removing the subsequent tokens including the matching \fi.

The previous sentence rephrased in other words:
Expanding the \else of an \if..\else..\fi while the \if..-condition is fulfilled yields removal of the tokens that form the "false"-branch and removal of the matching \fi.

E.g., (click the image to enlarge)

enter image description here

yields: (click the image to enlarge)

enter image description here

yields: (click the image to enlarge)

enter image description here

Expanding the \if.. of an \if..\else..\fi while the \if..-condition is not fulfilled yields evaluation and removal of the tokens that are needed for finding out whether the \if..-condition is fulfilled and removal of all tokens that form the "true"-branch, including the \else-token that marks the end of the "true"-branch.

(Expansion of the \else of an \if..\else..\fi while the \if..-condition is not fulfilled does not occur: As just said: In this case the token \else is removed as the marker of the end of the "true"-branch. As it is removed it cannot be expanded.)

E.g., expanding the \ifnum of

\ifnum1=2 equal\else different\fi

yields: different\fi.

different is carried out. After that \fi is carried out=expanded=removed.

Be aware that the term "evaluation" in the phrase "evaluation and removal of the tokens that are needed for finding out whether the \if..-condition is fulfilled" with some \if..-conditionals subsumes expansion of expandable tokens—this is the case, e.g., with \if and \ifcat—and with some \if..-conditionals does not subsume expansion of expandable tokens—this is the case, e.g., with \ifx. With some \if..-conditionals—e.g., \ifhmode, \ifvmode, \ifmmode, \ifinner— no tokens at all are needed for finding out whether the \if..-condition is fulfilled.


Let's look at your definition of \mySection:

\newcommand\mySection[2]{
    \ifnum #2=1 
    \expandafter\expandafter\expandafter\section
    \else\section*
    \fi
    {#1}
}

With your code in case of #2 being 0 the tokens forming the "true"-branch of \mySection's \ifnum..\else..\fi are discarded whereby the token \else denotes the end of the "true"-branch and is discarded, too. The tokens behind the \else forming the "false"-branch are not discarded but are carried out. The token \fi belonging to \mySection's \ifnum..\else..\fi is not removed from the input-stack before carrying out \section*. Therefore the argument of \section* will be the token \fi, not the sequence {#1}. Expanding the \section-macro/expanding macros underlying the \section-macro means replacing the control-sequence-token in question by its definition-text while inserting the arguments for the parameters. Hereby the \fi coming as \section*'s argument erroneously matches up some \if..-⟨some parameter #1/#2/whatever⟩-\else-\fi-expression coming from the definition-text of some macro underlying the \section-command. Thus the \else behind ⟨some parameter #1/#2/whatever⟩ is considered an extra \else.
(The \fi behind what is considered an extra \else is not considered an extra \fi but "helps" matching things up instead of the \fi belonging to \mySection's \ifnum..\else..\fi which is consumed as \section*'s argument.)

With your code in case of #2 being 1 the first \expandafter-chain (consisting of the 1st and the 3rd \expandafter) "hits" the \else. Therefore \else gets expanded (and hereby removed) which yields the discarding of the entire "false"-branch including the \fi which marks the end of the "false"-branch. The second \expandafter-chain (consisting of the second \expandafter) then "hits" the { of {#1} which has no effect as { is not expandable.


In case #2=1 have TeX remove the * of the sequence \section* via \@firstoftwo:

\documentclass{aricle}

\makeatletter
\newcommand\mySection[2]{%
  \ifnum#2=1 \expandafter\@firstoftwo\fi\section*{#1}%
}%
\makeatother

\begin{document}
    test
\mySection{title}{1}
\mySection{title}{0}

\end{document}

If you don't like \expandafter you can \exchange \@firstoftwo and \fi:

\documentclass{article}

\makeatletter
\newcommand\exchange[2]{#2#1}%
\newcommand\mySection[2]{%
  \ifnum #2=1 \exchange\@firstoftwo\fi\section*{#1}%
}%
\makeatother

\begin{document}
    test
\mySection{title}{1}
\mySection{title}{0}

\end{document}
2
  • Thank you very much for the detailed explanation. It gives me an idea how to approach my scenario. While it seems to work it fails in my given scenario. I raised another question tex.stackexchange.com/q/579233/48642. Perhaps you can point out why your proposed solution fails. Would be out of curiosity. – LeO Jan 17 at 16:49
  • Although I figured out that you use your sample just for demonstration I didn't succeed to apply it correctly (following the standard solution proposed by egreg) – LeO Jan 17 at 17:42
3

A standard way to do this job is

\documentclass{article}

\makeatletter
\newcommand\mySection[2]{%
  \ifnum #2=1
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\section}{\section*}{#1}%
}
\makeatother

\begin{document}

test
\mySection{title}{1}
\mySection{title}{0}

\end{document}

so the conditional is completely removed before choosing the desired path.

There are many other ways, even some that require no \expandafter.

\documentclass{article}
\usepackage{etoolbox}

\newcommand\mySection[2]{%
  \ifnumcomp{#2}{=}{1}{\section}{\section*}{#1}%
}

\begin{document}

test
\mySection{title}{1}
\mySection{title}{0}

\end{document}

Without packages (but a fairly recent LaTeX kernel)

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand\mySection{mm}
 {
  \int_compare:nTF {#2=1}{\section}{\section*}{#1}
 }
\ExplSyntaxOff

\begin{document}

test
\mySection{title}{1}
\mySection{title}{0}

\end{document}

The last one can be extended to support the optional argument.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand\mySection{O{#2}mm}
 {
  \int_compare:nTF {#3=1}{\section[#1]}{\section*}{#2}
 }
\ExplSyntaxOff

\begin{document}

\tableofcontents

\mySection[short title for toc]{title}{1}
\mySection{title}{0}

\end{document}

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.