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.

I want to define a macro \create that accept a single mandatory argument from which another new macro is created and named.

The following code snippet may speak clearer what I want to achieve. But the following code cannot be compiled because it is wrong. :-)

\documentclass{article}

\newcommand\create[1]{%
\newcommand\#1{My name is #1}}

\begin{document}
\create{test}
\test
\end{document}

How to define a macro to create a new macro with a name passed as its argument?

share|improve this question
    
    
@xport Check my code on about line 2 (command factory) at tex.stackexchange.com/questions/13333/… –  Yiannis Lazarides Aug 28 '11 at 17:56

3 Answers 3

up vote 18 down vote accepted

Use \csname #1\endcsname which must be expanded before \newcommand using \expandafter:

\newcommand\create[1]{%
\expandafter\newcommand\csname #1\endcsname{My name is #1}}
% usage: \create{foobar}

If you want to pass the macro as control sequence instead, i.e. \foobar instead of foobar then you need to turn it into a string and remove the backslash:

\makeatletter
\newcommand\create[1]{%
\expandafter\newcommand\csname\expandafter\@gobble\string#1\endcsname{My name is #1}}
\makeatother
% usage: \create{\foobar}

There is also the \@namedef macro which is defined as \expandafter\def\csname #1\endcsname, so you can use it as:

\newcommand\create[1]{\@namedef{My name is #1}}

The etoolbox package also provides a basically identical, but robust macro called \csdef. For both you can provide a parameter text, e.g. for arguments direct after the name argument: \csdef{name}#1#2{some code with two arguments #1 and #2} (the # have to be doubled inside another macro).

share|improve this answer
    
Unbelievable. You beat me to it by 49 seconds! –  Ian Thompson Aug 11 '11 at 8:59
    
I guess that the fact you're using \newcommand (with the benefits that that brings) is why you didn't mention \@namedef. –  Loop Space Aug 11 '11 at 9:01
3  
@Andrew: Yes, also \@namedef requires \makeatletter ... \makeatother, which is a little annoying. However, for packaged code without optional arguments \@namedef{#1}{My name is #1} would also be an easy option. –  Martin Scharrer Aug 11 '11 at 9:05
1  
@xport: In this case you must define the macro globally, i.e. either use \global\@namdef{#1}{<content>} or, if you need \newcommand, \global\expandafter\let\csname #1\expandafter\endcsname\csname #1\endcsname. –  Martin Scharrer Aug 11 '11 at 9:55
2  
@xport: You didn't provide the real example to explain why grouping is necessary. There are many tricks to define a macro in group, e.g. {\def\x{\def\foo{bar}}\expandafter}\x. But you should firstly persuade us (and yourself) to believe that it is necessary to use these tricks. –  Leo Liu Aug 11 '11 at 10:22

If you're going to be doing lots of this sort of thing, you can create a bunch of macros in one go from a comma separated list with some etoolbox magic:

\usepackage{etoolbox}
\newcommand\create[1]{%
\expandafter\newcommand\csname #1\endcsname{My name is #1}}
\newcommand\createlist{%
\let\do\create
\docsvlist
}

The argument of \createlist should be a list like: \createlist{foo,Foo,magic,jabberwocky} and it will create \foo,\Foo,\magic,\jabberwocky

share|improve this answer
2  
With etoolbox, you can use \csdef, \csgdef then. –  Leo Liu Aug 11 '11 at 10:28
    
@Leo but then you don't have the protection from overwriting definitions that \newcommand gives you... –  Seamus Aug 11 '11 at 11:17
    
+1 I might need this technique in the future. Thanks. –  xport Aug 11 '11 at 11:50
    
With the help of a simple shell script, you can use this to get a list of all the filenames of images in a directory, and create a command that includes each one... (That's what I used it for.) –  Seamus Aug 11 '11 at 12:26
\documentclass{article}

\newcommand\create[1]{%                                                         
\expandafter\def\csname #1\endcsname{My name is #1}}

\begin{document}
\create{test}
\test
\end{document}
share|improve this answer

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.