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.

Ger
  • 187
  • 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

4 Answers4

6

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

egreg
  • 1,121,712
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}
Werner
  • 603,163
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}
David Carlisle
  • 757,742