11

In "Defining a newcommand, with variable name, inside another newcommand" we learned how to use \newcommand within a command definition with another \newcommand, when the name of the inner command needs to contain a parameter of the outer command. Now, suppose I want to do the same, but for the inner \newcommand to also have parameters, i.e. I want the following code to work:

\newcommand{\defsilly}[1]{%
  % define a command named silly#1 , taking a single parameter
}
\defsilly{willy}
\sillywilly{theparameter}

Motivation: I'm writing a thesis document class, which has a bunch of the following kind of command pairs:

\newcommand{\iitthesis@authorEnglish}{Name of Author}
\newcommand{\authorEnglish}[1]{\renewcommand{\iitthesis@authorEnglish}{#1}}

I want to replace each of these pairs with something like:

\iitthesis@thesisdatafield{authorEnglish}{Name of Author}

This defines both the above commands.

2
  • When a newcommand is defined within the newcommand the inner newcommand needs to use ##1 to access its first parameter, as #1 refers to the parents first parameter. Also, need to use makeatletter, maketatother around commands that use an @ sign in them. Commented Nov 13, 2011 at 17:04
  • 1
    Please stop calling new commands (macros) as "a \newcommand". The \newcommand macro defines new commands, but these aren't "a \newcommand". What are your trying to do now? Define a new macro given by name (plus prefix) or a new version of \newcommand? Commented Nov 13, 2011 at 17:10

2 Answers 2

8
\newcommand{\iitthesis@thesisdatafield}[2]{%
  \@namedef{iitthesis@#1}{#2}}

With

\iitthesis@thesisdatafield{authorEnglish}{Name of Author}

you'd define \iitthesis@authorEnglish to expand to "Name of Author", that is, you'd have issued the equivalent of

\def\iitthesis@authorEnglish{Name of Author}

This wouldn't check for the defined command to be previously undefined. If you want also this check, do

\newcommand{\iitthesis@thesisdatafield}[2]{%
  \expandafter\@ifdefinable\csname iitthesis@#1\endcsname
    {\@namedef{iitthesis@#1}{#2}}}

but for internal commands this isn't usually done.

In your motivation I don't see any need of defining the new command with an argument. If you need also to define a user level command, you can do with the same technique:

\newcommand{\iitthesis@thesisdatafield}[1]{%
  \long\@namedef{#1}##1{\@namedef{iitthesis@#1}{##1}}}

In this case saying

\iitthesis@thesisdatafield{authorEnglish}

would define the command \authorEnglish so that if the user types

\authorEnglish{A. U. Thor}

the effect would be as if doing

\def\iitthesis@authorEnglish{A. U. Thor}

The \long prefix to \@namedef causes \long\def to be executed, so the argument can span one or more paragraphs.

This technique is employed by the LaTeX kernel, where \author{A. U. Thor} actually defines \@author expanding eventually to "A. U. Thor".

2
  • You might want to mention the makeatletter...\makeatother issue and add it around the code. Commented Nov 13, 2011 at 17:29
  • 1
    @PeterGrill The OP is quite clear about doing this in a class file, where @ is a letter.
    – egreg
    Commented Nov 13, 2011 at 17:30
9

As in the other question, you need to use \csname .. \endcsname to build the macro name and \expandafter to expand it to that name before you are using \newcommand (or similar) to define that macro. Simply append the optional parameter argument after \endcsname.

\newcommand{\iitthesis@thesisdatafield}[2]{%
   \expandafter\newcommand\csname iitthesis@#1\endcsname{#2}%
   \expandafter\newcommand\csname #1\endcsname[1]{\expandafter\renewcommand\csname iitthesis@#1\endcsname{##1}}%
}

Note that you need to double the # for the argument in the inner macro, so that it is clear it isn't the first argument of the outer one.

There is the \@namedef{<name>}<parameter text>{<macro code>} macro which does basically the same, but using the TeX primitive \def, not LaTeX's \newcommand. The basic difference is that it doesn't check if the macro exists yet and defines it in any case and that you have to list the parameters in plain form: #1 instead of [1], #1#2 instead of [2] etc.

2
  • You might want to mention the makeatletter...\makeatother issue and add it around the code. Commented Nov 13, 2011 at 17:28
  • 2
    @PeterGrill: The OP stated the code is for a class, so this is not required. Commented Nov 13, 2011 at 17:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .