23

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?

27

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).

  • 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
  • @xport: Yes, using \gdef` instead of \newcommand will do it as well. – Martin Scharrer Aug 11 '11 at 10:15
  • 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
  • @Leo: If you are interested in avoiding grouping, see my answer. I just applied what I learnt from this question. – xport Aug 11 '11 at 11:41
6
\documentclass{article}

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

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

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

  • 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

If you want to pass the macro name as a macro name:

\documentclass{article}

\newcommand{\create}[1]% #1 = macro name
{\bgroup
  \def\foo{Hello World!}% local definition
  \global\let#1=\foo
\egroup}

\begin{document}
\create{\mymacro}%
\mymacro
\end{document}
  • What's the difference between this and \newcommand\create[1]{\def#1{Hello World!}}? Sorry, I don't know much about tex subtleties. – coldfix Sep 20 '17 at 21:34
  • @coldfix - I knew \let would work. I wasn't sure about \def, especially if the macro itself has arguments: – John Kormylo Sep 21 '17 at 3:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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