GeneralCalling macros with arguments - using \csname

LaTeX specific issues not fitting into one of the other forums of this category.
gkamel
Posts: 25
Joined: Thu Oct 30, 2008 1:53 pm

Calling macros with arguments - using \csname

Post by gkamel »

Is it possible to call a macro that takes in an argument, using the \csname primitive?

For example, if I have the following macro definition:

Code: Select all

\newcommand\MyMacro{
Hello world!
}
it can be called using:

Code: Select all

\csname MyMacro\endcsname
But if I have:

Code: Select all

\newcommand\MyMacro[1]{
Hello #1!
}
then

Code: Select all

\csname MyMacro{world}\endcsname
doesn't have quite the intended effect..

George

Recommended reading 2024:

LaTeXguide.org • LaTeX-Cookbook.net • TikZ.org

NEW: TikZ book now 40% off at Amazon.com for a short time.

josephwright
Site Moderator
Posts: 814
Joined: Tue Jul 01, 2008 2:19 pm

Calling macros with arguments - using \csname

Post by josephwright »

Two things here. First, \newcommand is a LaTeX command, whereas \csname is a TeX primitive command. So the syntax is different. Second, \csname does not define anything: you need to use the TeX primitive \def. This also requires the \expandafter primitive.

To create a macro with arguments using \def, you give the arguments as #1, #2, and so on:

Code: Select all

\def\MyMacro#1{Some code #1}
and so with \csname:

Code: Select all

\expandafter\def\csname MyMacro\endcsname#1{Some code #1}
What happens here is that TeX sees the \expandafter, and moves on to \csname (constructing the name) before using \def to create the new macro. If you try this without the \expandafter things go wrong.

LaTeX provides and internal macro which covers up some of the messy detail:

Code: Select all

\makeatletter
\@namedef{MyMacro}#1{Some code #1}
\makeatother
has exactly the same effect as the primitive version above.
Joseph Wright
User avatar
nlct
Posts: 276
Joined: Thu Nov 06, 2008 11:15 am

Calling macros with arguments - using \csname

Post by nlct »

gkamel wrote:

Code: Select all

\csname MyMacro{world}\endcsname
doesn't have quite the intended effect..
\csname MyMacro\endcsname expands to \MyMacro, so to get \MyMacro{world} you need to do

Code: Select all

\csname MyMacro\endcsname{world}
If you put {world} inside the \csname...\endcsname you make it a part of the command name rather than a separate object that happens to follow the command name.

Regards
Nicola Talbot
gkamel
Posts: 25
Joined: Thu Oct 30, 2008 1:53 pm

Calling macros with arguments - using \csname

Post by gkamel »

Many thanks for the replies.

Joseph, I was actually looking for a way to call the macro using \csname rather than defining it. But what you have suggested may nevertheless come in handy for me later.

Nicola, the code you have given works fine if the macro is defined, but I need it to not display anything if the macro is undefined, which I didn't make clear in my initial post. So I thought of building on your suggestion by defining a wrapper macro as follows:

Code: Select all

\newcommand\DisplayOutput[2]{
\ifthenelse{\isundefined{#1}}{}{\csname#1\endcsname{#2}}
}
and calling:

Code: Select all

\DisplayOutput{\MyMacro}{world}
which works fine if the macro is undefined, but if it's defined, then the following error appears:
! Missing \endcsname inserted.
Any ideas?

With kind regards,

George
George Kamel
josephwright
Site Moderator
Posts: 814
Joined: Tue Jul 01, 2008 2:19 pm

Calling macros with arguments - using \csname

Post by josephwright »

Ah, sorry, mis-read things. I'd probably use the e-TeX primitive \ifcsname for this. I'd also use a few expansion tricks to make sure everything works out OK.

Code: Select all

\newcommand*{\DisplayOutput}[1]{%
  \def\tempa{\csname #1\endcsname}%
  \def\gobbleone##1{}%
  \ifcsname #1\endcsname
    \expandafter\tempa
  \else
    \expandafter\gobbleone
  \fi
}
The idea here is that the \ifcsname ... \endcsname construct looks for the definition of #1. If it is found, \tempa is executed (and turns into \csname #1\endcsname), but the \expandafter means this happens after the \fi. On the other hand, if #1 is not defined \gobbleone will aborb the next token, again after the \fi because of the \expandafter.

You could do this without e-TeX, but the tools are there and make the code easier to follow.

Hope this helps.
Joseph Wright
phi
Posts: 577
Joined: Tue Oct 21, 2008 8:10 pm

Calling macros with arguments - using \csname

Post by phi »

The etoolbox package makes this a bit easier:

Code: Select all

\documentclass{article}

\usepackage{etoolbox}

\newrobustcmd*\TEST[2]{%
	\ifcsdef{#1}{\csuse{#1}{#2}}{}%
}


\begin{document}

No output:
\TEST{MyMacro}{world}

Now we define the macro
\newcommand*\MyMacro[1]{Hello #1!}

Output:
\TEST{MyMacro}{world}

\end{document}
gkamel
Posts: 25
Joined: Thu Oct 30, 2008 1:53 pm

Re: Calling macros with arguments - using \csname

Post by gkamel »

Many thanks for both of your suggestions... it works perfectly now.

Kind regards,

George
George Kamel
gkamel
Posts: 25
Joined: Thu Oct 30, 2008 1:53 pm

Calling macros with arguments - using \csname

Post by gkamel »

Dear Joseph,

It turns out I need to make use of your suggestion on how to define a macro with csname sooner than I thought.

I have the following:

Code: Select all

\def\temp{MyMacro}

and I'm using your suggestion:

Code: Select all

\expandafter\def\csname temp\endcsname#1{Some code #1}

to define a new macro called MyMacro. But when I call this macro, LaTeX complains that MyMacro is undefined.

Any ideas what the problem could be?

Kind regards,

George
josephwright
Site Moderator
Posts: 814
Joined: Tue Jul 01, 2008 2:19 pm

Re: Calling macros with arguments - using \csname

Post by josephwright »

Not without some context. Could you post an example?
Joseph Wright
gkamel
Posts: 25
Joined: Thu Oct 30, 2008 1:53 pm

Calling macros with arguments - using \csname

Post by gkamel »

Well, simply I have the following macro defined:

Code: Select all

\def\temp{MyMacro}
and I'd like to define a new macro whose name is the expansion of temp, in this case, MyMacro.

Perhaps your code was achieving something else, but I'd be grateful for your guidance in this, to save my remaining hair.

Thanks,

George
George Kamel
Post Reply