130

I would like to define a *'d version of a command, something like

\newcommand{\foo}{blah}
\newcommand{\foo*}{blahblah}

If I try to do this, LaTeX complains that I'm trying to redefine \foo, so I guess I need to do something special to handle *s. But what?

Neil Olver
  • 4,942

3 Answers3

89

If you look at source2e you might see a lot of lines that look like

\def\foo{\@ifstar\@foo\@@foo}
\def\@foo#1{...}
\def\@@foo#1{...}

This makes \foo a one-argument command that has regular and starred versions. The starred version is the expansion of \@foo while the nonstarred version is that of \@@foo. Using the @ sign in the auxiliary macros is a TeX convention which some authors embrace and some avoid.

There are higher-level ways to do it (as lockstep points out) but once you learn this pattern it's not too hard to use. Just make sure it's between \makeatletter...\makeatother or in a .sty file.

Edits removed some inaccuracies and editorializing.

lockstep
  • 250,273
Matthew Leingang
  • 44,937
  • 14
  • 131
  • 195
  • 1
    What's the controversy with @? FWIW, it's also used in Plain and ConTeXt (although far less in the latter, which do is more common, leading to some funny command names such as \dodohideblock). – Will Robertson Oct 22 '10 at 03:22
  • 2
    Let me be clear that I follow the @-convention and am not advocating against it. But I can also see the point of view that the name \@foo (or \f@o or \f@@) doesn't help the human reader understand the relationship. \@foowithstar and \@foowithoutstar might be better. Sorry if I blew that internal ambivalence into a controversy. :-) Also, I wanted to point out that @'s are not required in auxiliary macros. – Matthew Leingang Oct 22 '10 at 11:12
  • 14
    Yes, using '@' in place of vowels is a pain in the neck, whereas using it as a divider is fine. – Joseph Wright Oct 23 '10 at 17:39
85

See this entry in the TeX FAQ.

The "elegant" way is to use the suffix package (which requires eTeX):

\documentclass{article}

\usepackage{suffix} \newcommand\foo{blah} \WithSuffix\newcommand\foo*{blahblah}

\begin{document}

\foo

\foo*

\end{document}

lockstep
  • 250,273
  • Does this work with commands with optional arguments too? If so how? – jan-glx Mar 11 '14 at 10:59
  • 1
    @YAK I don't know. Note that the combination starred/optional is very rare. – lockstep Mar 11 '14 at 11:37
  • 1
    Ups, I meant normal arguments, not optionals. And it works (\WithSuffix\newcommand\foo*[1]{Foo #1}) but warns "No 2nd argument following newcommand"... – jan-glx Mar 11 '14 at 12:13
  • Maybe I misunderstood what you meant, and maybe the package has changed since then, but; \WithSuffix\newcommand\mycommand[3]{starred command #1 #2 #3} works fine (\mycommand{1}{2}{3}) – Mogu Jul 25 '19 at 09:22
  • 1
    Note that when using \WithSuffix, the name of the new command \foo* apparently cannot be surrounded by brackets {...} in the definition. – Paul Wintz Sep 25 '22 at 05:48
81

LaTeX3 solution:

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand\foo{s}{%
  \IfBooleanTF#1%
    {blahblah}% If a star is seen
    {blah}%     If no star is seen
}
Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
  • 1
    This was the only solution that worked for me when using \dekotenize in the command and invoking the command from the caption of a lstlisting. – Christoph Thiede Oct 05 '21 at 20:03