7

Consider the following code:

I'm trying to write a \newcommand that will accept either m or n arguments, where m < n. Here m=4, n=6. I want to set things up so that if I call a newcommand, and it is passed 6 arguments, it will ignore the latter two if \fl is defined.

The rationale for this is that I want to merge different commands depending on different options, but I want to call the commands in the same way.

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[4]
  {#1 #2 #3 #4}
\else
  \newcommand{\xx}[6]{%
    {#1 #2 #3 #4
      \begin{#5}
        \item foo
      \end{#6}
    }
  } \fi

\begin{document}
\xx{a}{b}{c}{d}{enumerate}{enumerate}
\end{document}

To be clear, I want to get

a b c d

if \fl is defined, and

a b c d
\begin{enumerate}
\item foo
\end{enumerate}

if it is not.

2
  • In the true branch do \newcommand{\xx}[6]{#1 #2 #3 #4}; where's the problem?
    – egreg
    Jun 4, 2014 at 21:12
  • @egreg I want to use the same code for both. Jun 4, 2014 at 21:12

4 Answers 4

5

Nothing requires you use all arguments in the replacement text:

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[6]
  {#1 #2 #3 #4}
\else
  \newcommand{\xx}[6]{%                                                                                                                                                    
    {#1 #2 #3 #4                                                                                                                                                           
      \begin{#5}                                                                                                                                                           
        \item foo                                                                                                                                                          
      \end{#6}                                                                                                                                                             
    }                                                                                                                                                                      
  } \fi

\begin{document}                                                                                                                              
\xx{a}{b}{c}{d}{enumerate}{enumerate}
\end{document}

Output when \fl is defined

enter image description here

Output when \fl is not defined

enter image description here

In order to get this, I just put % in front of \def\fl{}


If the status of \fl is changing in the document, a more complex strategy is necessary:

\documentclass{article}[12pt]

\makeatletter
\newcommand{\xx}[4]{%
  #1 #2 #3 #4%
  \ifdefined\fl
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\@gobbletwo}%
  {\xx@aux}%
}
\newcommand\xx@aux[2]{%
  \begin{#1}
    \item foo
  \end{#2}
}

\begin{document}
Here \verb+\fl+ is not defined

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\bigskip
\newcommand{\fl}{}

Here \verb+\fl+ is defined

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}

enter image description here

2

Here is a version that uses the xparse package to make parameters #5 and #6 optional.

If \fl is not defined, then we can process both a four parameter and a six parameter version, and report an error in case a 5 parameter version is encountered.

If \fl is defined, then we process a case of 4, 5, or 6 parameters as if it was a 4 parameter version.

enter image description here

Code:

\documentclass{article}
\usepackage{xparse}

\newcommand{\MyError}[3]{%
    Error: #1: #2 #3%
    %\PackageError{#1}{#2}{#3}% <-- Use this once code is debugged.
}%


\NewDocumentCommand{\xx}{m m m m g g}{%
    \ifdefined\fl
        % only the first four parameters are useful
        \xxFour{#1}{#2}{#3}{#4}%
    \else
        % Allow for 4 or 6 parameters
        \IfNoValueTF{#5}{%
            % #5 not provided, so default back to 4 parameter version
            \xxFour{#1}{#2}{#3}{#4}%
        }{%
            \IfNoValueTF{#6}{%
                % Only 5 parameters were provided
                \MyError{xx}{5 Parameters were provided. Required either 4 or 6 parameters since \textbackslash fl is not defined}{C}%
            }{%
                \xxSix{#1}{#2}{#3}{#4}{#5}{#6}%
            }%
        }%
    \fi
}%

\newcommand{\xxFour}[4]{%
    Four parameters: #1, #2, #3, #4
}%

\newcommand{\xxSix}[6]{%
    \begin{#5}
        \item Parameter 1: #1
        \item Parameter 2: #2
        \item Parameter 3: #3
        \item Parameter 4: #4
        \item Parameter 5: #5
        \item Parameter 6: #6
    \end{#6}
}%

\newcommand{\Test}{% so that we can repeat this 
\textbf{4 paramaters:}
\xx{a}{b}{c}{d}

\bigskip\par
\textbf{5 paramaters:}
\xx{a}{b}{c}{d}{enumerate}

\bigskip\par
\textbf{6 paramaters:}
\xx{a}{b}{c}{d}{enumerate}{enumerate}
}%

\begin{document}
\textbf{\textbackslash fl NOT defined}:

\Test

\bigskip\par
\def\fl{}
\textbf{\textbackslash fl defined}:

\Test

\end{document}
1

Here are some options (not extensively tested in your setup though):

Option A:

Define \xx to work on 4 or 6 arguments by peeking ahead and see whether a new group \bgroup is started.

enter image description here

\documentclass{article}

\makeatletter
\newcommand{\xx@}[2]{%
  #1 #2
}
\newcommand{\xx}[4]{%
  #1 #2 #3 #4
  \@ifnextchar\bgroup\xx@\relax
}
\makeatother

\begin{document}
\xx{a}{b}{c}{d}{enumerate}{enumerate}

\xx{a}{b}{c}{d}

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}

This, of course, does not take \fl into consideration. In the above example, \xx@ would contain the environment definition, effectively designated to handle the two last arguments.

Option B:

Use it as you specified:

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[4]{%
    #1 #2 #3 #4
  }
\else
  \newcommand{\xx}[6]{%
    #1 #2 #3 #4 #5 #6
  }
\fi

\begin{document}

\xx{a}{b}{c}{d}% or \xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}
1
  • The following example tests for fl inside the definition of \xx.

  • Also it uses the more natural switch \iffl instead of testing, if a macro is defined.

  • The number of arguments is reduced to 5, because \begin{#5} and \end{#6} should not have different arguments.

Example:

\documentclass{article}

\newif\iffl

\newcommand{\xx}[5]{%
  #1 #2 #3 #4%
  \iffl
    \begin{#5}
      \item foo
    \end{#5}%
  \fi
}

\begin{document}
  \flfalse
  \subsection*{Case: flfalse}
  \xx{a}{b}{c}{d}{enumerate}

  \subsection*{Case: fltrue}
  \fltrue
  \xx{a}{b}{c}{d}{enumerate}
\end{document}

Result

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .