Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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:

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

to work.

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}

which defines both the above commands.

share|improve this question
    
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. –  Peter Grill Nov 13 '11 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? –  Martin Scharrer Nov 13 '11 at 17:10
add comment

2 Answers

up vote 4 down vote accepted
\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".

share|improve this answer
    
You might want to mention the makeatletter...\makeatother issue and add it around the code. –  Peter Grill Nov 13 '11 at 17:29
    
@PeterGrill The OP is quite clear about doing this in a class file, where @ is a letter. –  egreg Nov 13 '11 at 17:30
    
I like your approach, but if I use the \@namedef-cum-##1 like you suggest, I get an error when doing \authorEnglish{really long text with several paragraphs}; it tells me Paragraph ended before authorEnglish was complete. If you're asking why I need multi-paragraph author names, think about \acknowledgementsEnglish –  einpoklum Nov 13 '11 at 18:19
    
@EyalRozenberg Add \long as I did in my edit –  egreg Nov 13 '11 at 18:53
add comment

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.

share|improve this answer
    
You might want to mention the makeatletter...\makeatother issue and add it around the code. –  Peter Grill Nov 13 '11 at 17:28
1  
@PeterGrill: The OP stated the code is for a class, so this is not required. –  Martin Scharrer Nov 13 '11 at 17:32
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.