4

I wonder if there is a way to create a command which can discriminate when there is an argument or not. I don't mean empty argument, I mean no argument at all.

Here an example

\newcommand{\mycommand}[1]{
\if \totallyempty
0
\elseif \empty 
1
\else 
%whatever
2
\fi
}

Testing

\mycommand

0

\mycommand[]

1

\mycommand[2]

2

UPDATE

Apologies, the command argument does not need to be in braces {}, as many pointed, the optional arguments should be []. My main concern was about the possibility of not especify the argument, e.g. \mycommand,\mycommand[],\mycommand[2].

Apologies for not explaining correctly. I changed in the main text. Regards.

SOLUTION

Thanks very much to all the solution submitted, they are all very creative and useful.

I had to select @egreg solution (https://tex.stackexchange.com/a/409770/105956) for the very easy to implement and clear code. Mention to @Phelype Oleinik and @David Carlisle for not use any package.

Thanks very much. Kind regards.

  • 2
    if the argument is optional it should be in [] not {} and you can define commands via \newcommand that can detect an optional argument. – David Carlisle Jan 10 '18 at 21:03
5

You can, but you shouldn't. Optional arguments should be delimited by [].

I hope that the command names are clear enough to tell what's my opinion on the matter.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF
\cs_new_eq:NN \IfEmptyTF \tl_if_empty:nTF
\ExplSyntaxOff


\NewDocumentCommand{\mybadcommand}{g}{%
  \IfNoValueTF{#1}
   {0}
   {%
    \IfEmptyTF{#1}% if you allow { } to represent case 1, use \IfBlankTF instead
      {1}
      {2}%
   }%
}

\NewDocumentCommand{\mygoodcommand}{o}{%
  \IfNoValueTF{#1}
   {0}
   {%
    \IfEmptyTF{#1}% if you allow [ ] to represent case 1, use \IfBlankTF instead
      {1}
      {2}%
   }%
}

\begin{document}

\mybadcommand

\mybadcommand{}

\mybadcommand{x}

\mygoodcommand

\mygoodcommand[]

\mygoodcommand[x]

\end{document}

enter image description here

4

xparse provides a g parameter specification:

An optional argument given inside a pair of TeX group tokens (in standard LaTeX, {...}), which returns -NoValue- if not present.

It goes against the convention of using [...] for optional arguments. However, the use-case exists.

enter image description here

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand{\mycommand}{ g }{%
  \IfValueTF{#1}
    {% https://tex.stackexchange.com/q/53068/5764
    \if\relax\detokenize{#1}\relax
      1%
    \else
      #1%
    \fi}
    {0}%
}

\begin{document}

\mycommand% 0

\mycommand{}% 1

\mycommand{1}% 1

\mycommand{2}% 2

\end{document}
  • 1
    g is evil: use [] delimiters for optional arguments. (I know you are not to blame:-) – David Carlisle Jan 10 '18 at 21:04
3

You can define two commands, one with no arguments, and one with a conditional for an empty argument, like this:

\documentclass{article}

\makeatletter
\newcommand{\mycommand}{%
 \@ifnextchar[{\mycommand@something}{\mycommand@nothing}%
}
\newcommand{\mycommand@nothing}{%
 0%
}
\newcommand{\mycommand@something}[1][]{%
\if\relax\detokenize{#1}\relax
 1%
\else
 #1%
\fi
}
\makeatother

\begin{document}

0\mycommand

1\mycommand[]

2\mycommand[2]

\end{document}

The main command is \mycommand. If the next character is an [ then it executes the \mycommand@something, otherwise, the \mycommand@nothing.

The \mycommand@something checks for an empty argument. If it is empty then the conditional is true, otherwise it is false.

I could not make it work with "curry brackets" because they have special meaning in TeX. I suppose that changing their catcode momentarily could work...

Edit:

As @egreg pointed out using very few words (two tokens :)), one can use \bgroup as a replacement for { and trick TeX to check for a { after the \mycommand. In this case, \mycommand can be used exactly as desired:

\documentclass{article}

\makeatletter
\newcommand{\mycommand}{%
 \@ifnextchar\bgroup{\mycommand@something}{\mycommand@nothing}%
}
\newcommand{\mycommand@nothing}{%
 0%
}
\newcommand{\mycommand@something}[1]{%
\if\relax\detokenize{#1}\relax
 1%
\else
 #1%
\fi
}
\makeatother

\begin{document}

0\mycommand

1\mycommand{}

2\mycommand{2}

\end{document}
  • 1
    You forgot to add a % after the \@ifnextchar-line. And changing the catcode of brackets seems like a bad idea (has to be done prior to the paragraph the command is used in, changing the syntax of each command in that paragraph). – Skillmon Jan 10 '18 at 20:33
  • @Skillmon Thanks! Fixed it. Indeed, I tried doing some bizarre \catcodeing inside \mycommand, but then noticed that it would not work because of what you said U_U. But honestly I think that (as far as the example goes), there is no harm in using []... – Phelype Oleinik Jan 10 '18 at 20:41
  • 1
    \@ifnextchar\bgroup – egreg Jan 10 '18 at 20:53
3

While it is technically possible to make {} delimited arguments optional you should not do it, it breaks all the LaTeX syntax guidelines. {} arguments denote mandatory arguments, [] delimted arguments are optional.

enter image description here

\documentclass{article}


\makeatletter
\def\mycommand{\@ifnextchar[\my@command{yippee no argument here}}
\def\my@command[#1]{Here I deal with an argument (#1) \if\relax\detokenize{#1}\relax(which is empty)\fi}

\makeatother
\begin{document}

\mycommand

\mycommand[]

\mycommand[zz]

\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.