# Define a New Macro via a Macro Using xparse Syntax

I am trying to set up a macro that defines a macro that is to be executed only once.

With what I learned from Define a Macro via Macro if Given Macro is not defined I can do that via the \expandafter\newcommand syntax. And indeed the MWE as below works and produces the desired output:

where the subsequent \HelloWorld and \HelloDude are ignored.

What I would like to do, is to learn how to use \NewDocumentCommand (instead of \newcommand) to define this new macro via a macro. My attempt (requires you to uncomment the \def at the top of the file) fails with

Illegal parameter number in definition of \reserved@a

Furthermore, am wondering if there is a way to define repeated parameters. That is instead of {m m} can I use something similar to with tabular where one can say \begin{tabular}{r*{3}{l}r} which is the identical to \begin{tabular}{rlllr}. This would save me from having to use \IfEqCasefor each possible number of parameters. I personally only need up to 3 so am ok with the slight duplication of code below, but though I'd ask in case there was some other syntax that I am not aware of.

## Notes:

• You need to uncomment the \def at the top to get the MWE below to fail.

## Code:

%% Uncomment the following \def to get the failing test case.
%\def\UseXparseForDefiningMacro{}% Works if commented out (in which case \newcommand{}{} is used to define macro)
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{xparse}
\usepackage{xcolor}

\makeatletter
\NewDocumentCommand{\DefineMeAMacroThatExecutesOnlyOnce}{m m m}{%
% #1 = csname to use
% #2 = number of parameters
% #3 = code to execute
\ifdefined\UseXparseForDefiningMacro
\IfEqCase{#2}{%
{0}{\expandafter\NewDocumentCommand\csname#1\endcsname{     }{% No paramater version
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}}%
{1}{\expandafter\NewDocumentCommand\csname#1\endcsname{  m  }{% 1 paramater version
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}}%
{2}{\expandafter\NewDocumentCommand\csname#1\endcsname{ m m }{% 2 paramater version
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}}%
}%
\else% ---------------------------------------------  This works!!
\expandafter\newcommand\csname#1\endcsname[#2]{%
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}%
\fi
}
\makeatother

\DefineMeAMacroThatExecutesOnlyOnce{HelloWorld}{0}{% Does not take any parameters
Hello World!%
}

\DefineMeAMacroThatExecutesOnlyOnce{HelloDude}{1}{% Take 1 parameter
Hello \textcolor{red}{#1}.%
}

\begin{document}

%% Section 1: Works if \UseXparseForDefiningMacro is NOT defined
\HelloWorld
\HelloWorld

%% Section 2: Works if \UseXparseForDefiningMacro is NOT defined
\HelloDude{Peter}
\HelloDude{John}

\end{document}

-
Out of curiosity, why don't you use the expl3 syntax? It makes much more sense when using xparse, in my opinion. I would imagine the solution would also be more concise. –  Sean Allred Jun 30 '14 at 21:42
@SeanAllred: Am embarrassed to admit it, but I can't quite read expl3 syntax yet. –  Peter Grill Jun 30 '14 at 22:34

You could do this but it's so wrong, why mix expl3 and etoolbox tests and why all the toggle stuff, if you want \foo to just execute once define it to be

 \def\foo{hello\let\foo\@empty}


No need for a separate toggle macro.

but anyway:

%% Uncomment the following \def to get the failing test case.
\def\UseXparseForDefiningMacro{}% Works if commented out (in which case \newcommand{}{} is used to define macro)
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{xparse}
\usepackage{xcolor}

\makeatletter
\NewDocumentCommand{\DefineMeAMacroThatExecutesOnlyOnce}{m m m}{%
% #1 = csname to use
% #2 = number of parameters
% #3 = code to execute
\ifdefined\UseXparseForDefiningMacro
\expandafter\NewDocumentCommand\csname#1\expandafter\endcsname
\expandafter{\romannumeral#2000}{%
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}%
\else% ---------------------------------------------  This works!!
\expandafter\newcommand\csname#1\endcsname[#2]{%
#3%                           Never executed this macro so go ahead an execute it,
\toggletrue{AlreadyIssued#1}% and remember that we did (so we don't do it again).
}%
}%
\fi
}
\makeatother

\DefineMeAMacroThatExecutesOnlyOnce{HelloWorld}{0}{% Does not take any parameters
Hello World!%
}

\DefineMeAMacroThatExecutesOnlyOnce{HelloDude}{1}{% Take 1 parameter
Hello \textcolor{red}{#1}.%
}

\begin{document}

%% Section 1: Works if \UseXparseForDefiningMacro is NOT defined
\HelloWorld
\HelloWorld

%% Section 2: Works if \UseXparseForDefiningMacro is NOT defined
\HelloDude{Peter}
\HelloDude{John}

\end{document}

-
Yeah, I always forget about the \def thing to stop things from happening again. Can you elaborate on the \expandafter{\romannumeral#2000} magic that is happening here. How does that become m m if #2=2? –  Peter Grill Jun 30 '14 at 22:38
\romannumeral2000 expands to mm –  egreg Jun 30 '14 at 23:07
@egreg: Wow, that is very clever!! An I was thinking that a loop would be needed... –  Peter Grill Jul 1 '14 at 3:11
@PeterGrill yes well it was fortunate you wanted m arguments (although using romannumeral and then changing m to whatever you need is a viable technique for replicating in general) –  David Carlisle Jul 1 '14 at 9:14

Here is a solution for this problem, using (perhaps abusing) only expl3 features. I'm not really sure about the usefulness of this code. ;-)

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\NewOnceMacro}{m m m}
{
\grill_new_once_macro:Nnn #1 { #2 } { #3 }
}

% an addition to the kernel functions
\cs_set_eq:NN \use_none: \prg_do_nothing:

\cs_new_protected:Npn \grill_new_once_macro:Nnn #1 #2 #3
{
\cs_set_eq:cc
{% the corresponding "do nothing" macro
\cs_to_str:N #1 -disabled
}
{% generate \use_none:<as many n's as #2>
use_none: \prg_replicate:nn { #2 } { n }
}
\use:x
{
\exp_not:n { \NewDocumentCommand { #1 } }
{ \prg_replicate:nn { #2 } { m } } % the right number of m's
}
{
% the first usage definition
#3
% then redefine the macro to do nothing
\cs_gset_eq:Nc #1 { \cs_to_str:N #1 -disabled }
}
}

\ExplSyntaxOff

\NewOnceMacro{\HelloWorld}{0}{Hello world}
\NewOnceMacro{\Hello}{1}{Hello #1}
\NewOnceMacro{\Foo}{2}{Your #1 is full of #2}

\begin{document}

\HelloWorld
\HelloWorld

\Hello{Peter}
\Hello{Grill}

\Foo{hovercraft}{eels}

I read in interface3 about \use:x “Any hash characters (#) in the argument must be doubled.” What does that mean? –  Manuel Jun 30 '14 at 22:46
@Manuel I'm not really using # inside \use:x, because #1 and #2 will be replaced with the arguments before \use:x is executed. Think to it as doing a \def inside a \def: if you want to use parameters to the inner \def you have to double #. –  egreg Jun 30 '14 at 22:51
I will not upvote this question, it is scratched. :P –  Paulo Cereda Jul 1 '14 at 10:31