# Defining a command to define an asterisk command

I have the following command \defmeta that defines two other commands (one starred and one unstarred)

\documentclass{article}
\usepackage{suffix}
\newcommand{\genericcmd}[3]{#1 #3 #2 }
\newcommand{\genericcmdstarred}[3]{ #1 starred, #3 #2}
\newcommand{\defmeta}[3]{
\expandafter\newcommand\csname #1\endcsname[1]{\genericcmd{#2}{#3}{##1}}
\WithSuffix\expandafter\newcommand\csname #1\endcsname *[1]{\genericcmdstarred{#2}{#3}{##1}}
}

\defmeta{mynewcommand}{Hello}{world}

\begin{document}
\mynewcommand{big}.
\mynewcommand*{big}.
\end{document}


This works perfectly. However, I wonder if there is a way to remove the dependency on suffix? I would like to not use the suffix package because I do not want to have unnecessary dependencies and as a way to learn more LaTeX magic.

• Asterix vs. Asterisk. Apr 3, 2016 at 19:45
• I would recommend using xparse and \NewDocumentCommand which supports this out of the box. It is part of the development of the LaTeX 3 project.
– cfr
Apr 3, 2016 at 19:46
• @HenriMenke But you must admit that Asterixed versions of commands would bring a bit of badly needed excitement to many documents!
– cfr
Apr 3, 2016 at 19:47

## 4 Answers

No dependencies on packages, only on the LaTeX kernel.

\documentclass{article}

\newcommand{\genericcmd}[3]{#1 #3 #2}
\newcommand{\genericcmdstarred}[3]{#1 starred, #3 #2}

\makeatletter
\newcommand\metadef[3]{%
\DeclareRobustCommand#1{%
\@ifstar{\csname s\string#1\endcsname}{\csname n\string#1\endcsname}%
}%
\@namedef{s\string#1}##1{\genericcmdstarred{#2}{#3}{##1}}%
\@namedef{n\string#1}##1{\genericcmd{#2}{#3}{##1}}%
}
\makeatother

\metadef{\mynewcommand}{Hello}{world}

\begin{document}

\mynewcommand{big}.

\mynewcommand*{big}.

\end{document}


More interesting, perhaps, is a definition without the need to define \genericcmd and \genericcmdstarred. The command \metadef has the same syntax as \newcommand (but no * version, which could be added with some more trickery), but with an argument more:

\metadef{<macro name>}[<args>]{<code for normal version>}{<code for starred version>}


Optional arguments to the defined macro are not allowed, use the following xparse based code for adding whatever list of arguments you want.

\documentclass{article}

\makeatletter
\newcommand{\metadef}[1]{%
\DeclareRobustCommand#1{%
\@ifstar{\csname s\string#1\endcsname}{\csname n\string#1\endcsname}%
}%
\edef\meta@def@name{\string#1}%
\meta@def
}
\newcommand\meta@def[3][0]{%
\expandafter\newcommand\csname n\meta@def@name\endcsname[#1]{#2}%
\expandafter\newcommand\csname s\meta@def@name\endcsname[#1]{#3}%
}
\makeatother

\metadef{\mynewcommand}[1]{Hello #1 world}{Hello starred, #1 world}

\begin{document}

\mynewcommand{big}.

\mynewcommand*{big}.

\end{document}


The same with suffix:

\documentclass{article}
\usepackage{suffix}

\makeatletter
\newcommand{\metadef}[1]{%
\def\meta@def@name{#1}%
\meta@def
}
\newcommand\meta@def[3][0]{%
\expandafter\newcommand\meta@def@name[#1]{#2}%
\WithSuffix\expandafter\newcommand\meta@def@name*[#1]{#3}%
}
\makeatother

\metadef{\mynewcommand}[1]{Hello #1 world}{Hello starred, #1 world}

\begin{document}

\mynewcommand{big}.

\mynewcommand*{big}.

\end{document}


The same with xparse, where you just have to remember of shifting by one the number of the arguments, because #1 is the possible *. The arguments to the “metadefined” macro must be expressed in xparse syntax, of course.

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\metadef}{mmmm}{%
\NewDocumentCommand{#1}{s#2}{%
\IfBooleanTF{##1}{#4}{#3}%
}%
}

\metadef{\mynewcommand}{m}{Hello #2 world}{Hello starred, #2 world}

\begin{document}

\mynewcommand{big}.

\mynewcommand*{big}.

\end{document}

• This looks great. I was trying to do something like this in the beginning but I didn't know about the \string and @namdef commands. Apr 3, 2016 at 20:15
• @Tohiko I added what I believe is a more interesting approach. Apr 3, 2016 at 20:20
• The 'more interesting' version is a neat trick.
– jon
Apr 3, 2016 at 20:41

I would recommend using xparse which is part of the work by the LaTeX 3 project developers.

The following emulates the code in the question except that it eliminates the spurious space caused by the unstarred version of the command.

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand \mynewcommand { s m }
{%
Hello
\IfBooleanT {#1}
{%
starred,
}%
#2 world%
}

\begin{document}
\mynewcommand{big}.
\mynewcommand*{big}.
\end{document}


• Your version does not define a command that defines a starred command ;-)
– user31729
Apr 3, 2016 at 21:07
• True. Was that the question? Maybe I just didn't get it.
– cfr
Apr 3, 2016 at 23:09
• Yes, that was the question, see the title ;-) Irony is that I answered it that way but it's disregarded. Seems to be my fate here, on TeX.SX ;-)
– user31729
Apr 4, 2016 at 9:10
• I guess I took the goal to be the starred command creation, with the question thinking that creating a new command to do that was necessary as opposed to the goal being the new command itself.
– cfr
Apr 4, 2016 at 11:36

No dependencies on packages, no dependencies on LaTeX kernel:).

\def\isnextchar#1#2#3{\toks0={#2}\toks1={#3}%
\let\tmp=#1\futurelet\next\isnextcharA}
\def\isnextcharA{\the\toks\ifx\tmp\next0\else1\fi\space}

\def\metadef#1#2#3{\def#1{\isnextchar*{\metadefA{#3}}{\metadefB{#2}}}}
\def\metadefA#1*{\def\tmp##1{#1}\tmp}
\def\metadefB#1{\def\tmp##1{#1}\tmp}

\metadef \mynewcommand {Hello ##1 world} {Hello starred, ##1 world}

\mynewcommand{big}.

\mynewcommand*{big}.


Here's a version without any package, using \@ifstar and relying on a moving argument, i.e. the #1 command sequence has no real argument, but \@ifstar looks for the * character and branches into the relevant command either doing this or the other version.

\documentclass{article}

\newcommand{\genericcmdunstarred}[3]{#1 #3 #2 }
\newcommand{\genericcmdstarred}[3]{ #1 starred, #3 #2}
\makeatletter
\newcommand{\defmeta}[3]{%
\expandafter\newcommand\csname #1\endcsname{%
\@ifstar{%
\genericcmdstarred{#2}{#3}%
}{%
\genericcmdunstarred{#2}{#3}%
}%
}%
}

\defmeta{mynewcommand}{Hello}{world}

\defmeta{foo}{And now for something}{different}

\begin{document}
\mynewcommand{big}.

\mynewcommand*{big}.

\foo{completely}

\foo*{completely}

\end{document}


• I guess this solution relies on the fact that the "variable" argument ("big" or "completely") that is passed to genericcmd is the last one, right? Apr 3, 2016 at 20:13
• @Tohiko: Yes, that's a possible caveat.
– user31729
Apr 3, 2016 at 20:14