Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

expand in macro

13 views
Skip to first unread message

Pierre

unread,
Oct 29, 2009, 7:56:07 AM10/29/09
to
hello,

I don't understand why I obtain with the following code "BB" and not
"AB". The \bar macro used in the \foo macro is not expanded ! why ?

Thank you for your help

%%%%%%%%%%%%%%%%%%%%%%

\documentclass{article}

\makeatletter
\def\foo#1{
\@namedef{toto#1}{\bar}
}
\makeatother

\begin{document}
\def\bar{A}
\foo{a}

\def\bar{B}
\foo{b}

\totoa
\totob
\end{document}

Enrico Gregorio

unread,
Oct 29, 2009, 8:14:52 AM10/29/09
to
Pierre <pjo...@gmail.com> wrote:

Because that's the rule. The expansion of \foo{a} is

" \@namedef{totoa}{\bar}"
" \expandafter\def\csname totoa\endcsname{\bar}"
" \def\totoa{\bar}"

(notice the space) and these are the commands that reach TeX's
stomach. TeX never expands the replacement text in a \def.

When you call \totoa\totob you are essentially substituting them with
the /current/ meaning of \bar, which is always "B".

If you want to "freeze" the replacement text at definition time,
then \edef is what you need. The kernel of LaTeX doesn't provide
\@nameedef, which might be defined by

\def\@nameedef#1{\expandafter\edef\csname#1\endcsname}

But watch your step: that \edef might do evil things.

Ciao
Enrico

Pierre

unread,
Oct 29, 2009, 9:03:34 AM10/29/09
to
Thank you,

I obtain the expected result.

Merci
Pierre

\documentclass{article}

\makeatletter


\def\@nameedef#1{\expandafter\edef\csname#1\endcsname}

\def\foo#1{
\@nameedef{toto#1}{\bar}

Ulrich D i e z

unread,
Oct 29, 2009, 12:11:05 PM10/29/09
to
Enrico Gregorio wrote:

> \def\@nameedef#1{\expandafter\edef\csname#1\endcsname}
>
> But watch your step: that \edef might do evil things.

How about using \expandafter instead of \edef?

\def\@expandnamedef#1{%
\expandafter\def\csname#1\expandafter\endcsname\expandafter
}

\def\foo#1{\@expandnamedef{toto#1}{\bar}}

\def\bar{A}
\foo{a}

->\@expandnamedef{totoa}{\bar}
-> \expandafter\def\csname totoa\expandafter\endcsname\expandafter{\bar}
-> \expandafter\def\csname totoa\endcsname{A}
-> \def\totoa{A}


You can also play around with \romannumeral-expansion and
left-brace-delimited arguments in order to control the
amount of expansion-steps.

(I assume the code below --especially \@expandtimes-- can be shortened,
while I just don't see how. )

Ulrich


\documentclass{article}
\makeatletter
%%---------------------------------------------------------------
%% If _one_ \expandafter-chains hits
%% \romannumeral\@expandtimes{N}<Argument> , then _N_ expandafter-
%% chains will hit on the place of <Argument>
%%...............................................................
\newcommand\@expandtimes[1]{%
`\^^00%
\expandafter\@@@expandtimes
\expandafter{\romannumeral\number\number#1 000}{}%
}
\newcommand\@@@expandtimes[2]{%
\ifx A#1A\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\noexpand}{%
\expandafter\ifx\expandafter A\@gobble#1A%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\expandafter\noexpand#2\romannumeral`\^^00\expandafter\noexpand}{%
\expandafter\@@@expandtimes
\expandafter{\@gobble#1}%
{#2\romannumeral`\^^00\expandafter\expandafter\expandafter\noexpand}%
}%
}%
}
%%---------------------------------------------------------------
%% \@expandtimesnamedef{name}{N}{<Definition>}
%% N expandafter-chains will hit on the place of <Definition>
%% before defining the control-sequence \name takes place
%% in terms of \def.
%%...............................................................
\newcommand\@expandtimesnamedef[3]{%
\expandafter\def\csname#1\expandafter
\endcsname\expandafter{\romannumeral\@expandtimes{#2}#3}%
}
%%---------------------------------------------------------------
%% \@expandtimesname
%% <token-sequence A>{name}<token-sequence B>{N}{<token-sequence C>}
%%
%% <token-sequence A> and the control-sequence-token \<name> will be
%% placed in front of <token-sequence B> and the result from hitting
%% the place of <token-sequence C> with N \expandafter-chains
%%
%% e.g.,:
%%
%% \@expandtimesname
%% <definition-command>{control-sequence-name}<parameter-text>{N}{<definition-text>}
%%...............................................................
\newcommand\exchange[2]{#2#1}
\newcommand\@expandtimesname{}%
\newcommand\@@expandtimesname{}%
\long\def\@expandtimesname#1#{\@@expandtimesname{#1}}
\long\def\@@expandtimesname#1#2#3#{%
\@@@expandtimesname{#1}{#2}{#3}%
}
\newcommand\@@@expandtimesname[5]{%
\expandafter\exchange\expandafter{%
\csname#2\expandafter\exchange\expandafter{\expandafter{%
\romannumeral\@expandtimes{#4}#5%
}}{\endcsname #3}%
}{#1}%
}

\def\one{\two1 }
\def\two{\three2 }
\def\three{\four3 }
\def\four{\five4 }
\def\five{\six5 }
\def\six{6 }

\begin{document}

\ttfamily

|\expandafter\string\romannumeral\@expandtimes{0}\one|

|\expandafter\string\romannumeral\@expandtimes{1}\one|

|\expandafter\string\romannumeral\@expandtimes{2}\one|

|\expandafter\string\romannumeral\@expandtimes{3}\one|

|\expandafter\string\romannumeral\@expandtimes{4}\one|

|\expandafter\string\romannumeral\@expandtimes{5}\one|

|\expandafter\string\romannumeral\@expandtimes{6}\one|

%-----

\@expandtimesnamedef{test}{0}{\one etc} \meaning\test

\@expandtimesnamedef{test}{1}{\one etc} \meaning\test

\@expandtimesnamedef{test}{2}{\one etc} \meaning\test

\@expandtimesnamedef{test}{3}{\one etc} \meaning\test

\@expandtimesnamedef{test}{4}{\one etc} \meaning\test

\@expandtimesnamedef{test}{5}{\one etc} \meaning\test

\@expandtimesnamedef{test}{6}{\one etc} \meaning\test

%-----

\@expandtimesname \global\long\def{test}#1#2{0}{\one etc #1 and #2} \meaning\test

\@expandtimesname \renewcommand*{test}[2]{1}{\one etc #1 and #2} \meaning\test

\@expandtimesname \long\def{test}#1#2{2}{\one etc #1 and #2} \meaning\test

\@expandtimesname \renewcommand{test}[2]{3}{\one etc #1 and #2} \meaning\test

\@expandtimesname \long\def{test}#1#2{4}{\one etc #1 and #2} \meaning\test

\@expandtimesname \def{test}#1#2{5}{\one etc #1 and #2} \meaning\test

\@expandtimesname \long\def{test}#1#2{6}{\one etc #1 and #2} \meaning\test

\end{document}

Message has been deleted
Message has been deleted

Ulrich D i e z

unread,
Oct 30, 2009, 10:19:02 PM10/30/09
to
I wrote:

> The following is shorter:

>
> %%---------------------------------------------------------------
> %% If _one_ \expandafter-chains hits
> %% \romannumeral\@expandtimes{N}<Argument> , then _N_ expandafter-
> %% chains will hit on the place of <Argument>
> %%...............................................................
> \newcommand\@expandtimes[1]{%
> `\^^00\csname noexpand\expandafter\@@@expandtimes
> \romannumeral\number\number#1 000D\endcsname
> }
> \newcommand\@@@expandtimes[1]{%
> \if#1m%
> \expandafter\expandafter\csname endcsname\expandafter\@@@expandtimes\fi}
> %%---------------------------------------------------------------

Of course using "\csname noexpand" is not a good idea
as \romannumeral will consume a trailing space-token
after \noexpand anyway. :-(

In LaTeX you can use "\csname space" instead:

\newcommand\@expandtimes[1]{%
0\csname space\expandafter\@@@expandtimes
\romannumeral\number\number#1 000D\endcsname
}
\newcommand\@@@expandtimes[1]{%
\if#1m%
\expandafter\expandafter\csname endcsname\expandafter\@@@expandtimes\fi}


Or you define your own \romannumeral-stopper:

\newcommand*\@rmstop{0 }%
\newcommand\@expandtimes[1]{%
\csname @rmstop\expandafter\@@@expandtimes
\romannumeral\number\number#1 000D\endcsname
}
\newcommand\@@@expandtimes[1]{%
\if#1m%
\expandafter\expandafter\csname endcsname\expandafter\@@@expandtimes\fi}


With the helper-macro \exchange you can in LaTeX also get everything
into one macro:

\newcommand\@expandtimes[1]{%
\@firstoftwo{%
0\csname space%
\exchange{\romannumeral\number\number#1 000D\endcsname}%
}{%
\if#1D\expandafter\@gobble\else\expandafter\expandafter
\csname endcsname%
\exchange\fi
}%
{%
\expandafter\@firstoftwo\csname @secondoftwo\expandafter
\expandafter\expandafter\endcsname
\expandafter\@expandtimes
}%
}

Ulrich


\documentclass{article}
\makeatletter
%%---------------------------------------------------------------
%% If _one_ \expandafter-chains hits
%% \romannumeral\@expandtimes{N}<Argument> , then _N_ expandafter-
%% chains will hit on the place of <Argument>
%%...............................................................
\newcommand\@expandtimes[1]{%

0\csname space\expandafter\@@@expandtimes
\romannumeral\number\number#1 000D\endcsname
}
\newcommand\@@@expandtimes[1]{%
\if#1m%
\expandafter\expandafter\csname endcsname\expandafter\@@@expandtimes\fi}

\long\def\@expandtimesname#1#{\romannumeral\@@expandtimesname{#1}}


\long\def\@@expandtimesname#1#2#3#{%
\@@@expandtimesname{#1}{#2}{#3}%
}
\newcommand\@@@expandtimesname[5]{%
\expandafter\exchange\expandafter{%
\csname#2\expandafter\exchange\expandafter{\expandafter{%
\romannumeral\@expandtimes{#4}#5%
}}{\endcsname #3}%

}{0 #1}%

Pluto

unread,
Nov 3, 2009, 11:22:28 AM11/3/09
to
> %% <definition-command>{control-sequence-name}<parameter-text>{N}{<definition-­text>}
> \end{document}- Hide quoted text -
>
> - Show quoted text -

So what is the advantage of the chains of \expandafters over \edef.
You didn't say so. :)

Ulrich D i e z

unread,
Nov 3, 2009, 2:34:34 PM11/3/09
to
Pluto wrote:

> So what is the advantage of the chains of \expandafters

Actually I tried to provide means for _reducing_ the amount of
\expandafters by introducing
\romannumeral\@expandtimes{N}<stuff to expand N times> ...

> over \edef.
> You didn't say so. :)

I wouldn't call it "advantage". There are aspects which
might in some situations lead to preferring one or the
other approach.

1. \edef is an assignment.
You cannot use it in expansion-contexts.
Especially not _within_ another assignment if you actually
need the \edef to have taken place before that other
assignment.
You would have to perform that other assignment
in terms of \edef. Sometimes you don't want that.
Sometimes it doesn't matter. Sometimes you need
means of controlling the expansion-order even within
\edef.

2. \edef performs total expansion while \expandafter,
\romannumeral, \csname, \@expandtimes, \noexpand
etc can be used as means for controlling both the order
in which stuff gets expanded and the amount of
expansion-steps that one actually wants to have
performed.
There are situations where this is important and there
are situations where this is not important.

Ulrich

Pluto

unread,
Nov 5, 2009, 3:20:00 PM11/5/09
to

>" \@namedef{totoa}{\bar}"


>" \expandafter\def\csname totoa\endcsname{\bar}"
>" \def\totoa{\bar}"
>
>(notice the space)

Why the space, please?

Joseph Wright

unread,
Nov 5, 2009, 3:28:32 PM11/5/09
to
Pluto wrote:

>> " \@namedef{totoa}{\bar}"
>> " \expandafter\def\csname totoa\endcsname{\bar}"
>> " \def\totoa{\bar}"
>>
>> (notice the space)
>
> Why the space, please?

If you put

\def\csnametotoa\endcsname

then TeX looks for a macro called "\csnametotoa", whereas you want to
use \csname ... \endcsname to construct one called \totoa.
--
Joseph Wright

Ulrich D i e z

unread,
Nov 5, 2009, 5:45:13 PM11/5/09
to
Pluto wrote:

>On Nov 3, 7:34 pm, Ulrich D i e z <eu_angel...@web.de> wrote:

[...]
>> Ulrich

>>" \@namedef{totoa}{\bar}"
>>" \expandafter\def\csname totoa\endcsname{\bar}"
>>" \def\totoa{\bar}"
>>
>>(notice the space)

>Why the space, please?

The lines above did not come from me.
They are from a posting of Enrico Gregorio -
news:291020091314525445%greg...@math.unipd.it

There you find:

| Pierre <pjo...@gmail.com> wrote:
|
| > hello,
| >
| > I don't understand why I obtain with the following code "BB" and not
| > "AB". The \bar macro used in the \foo macro is not expanded ! why ?
| >
| > Thank you for your help
| >
| > %%%%%%%%%%%%%%%%%%%%%%
| >
| > \documentclass{article}
| >
| > \makeatletter
| > \def\foo#1{
| > \@namedef{toto#1}{\bar}
| > }
| > \makeatother
| >
| > \begin{document}

| > \def\bar{A}
| > \foo{a}
| >

| > \def\bar{B}
| > \foo{b}
| >
| > \totoa
| > \totob
| > \end{document}
|
| Because that's the rule. The expansion of \foo{a} is
|

| " \@namedef{totoa}{\bar}"
| " \expandafter\def\csname totoa\endcsname{\bar}"
| " \def\totoa{\bar}"
|

| (notice the space) and these are the commands that reach TeX's
| stomach. TeX never expands the replacement text in a \def.
|
| When you call \totoa\totob you are essentially substituting them with
| the /current/ meaning of \bar, which is always "B".
|
| If you want to "freeze" the replacement text at definition time,
| then \edef is what you need. The kernel of LaTeX doesn't provide
| \@nameedef, which might be defined by
|

| \def\@nameedef#1{\expandafter\edef\csname#1\endcsname}
|
| But watch your step: that \edef might do evil things.
|

| Ciao
| Enrico

I think Enrico Gregorio wanted to point out that Pierre's definition

|> \def\foo#1{
| > \@namedef{toto#1}{\bar}
| > }

yields an unwanted space-token after the curly opening-brace
and before the \@namedef.
That's why he also put a space behind the first " in each of the
lines of his description of the "flow of expansion".

| " \@namedef{totoa}{\bar}"
| " \expandafter\def\csname totoa\endcsname{\bar}"
| " \def\totoa{\bar}"

Ulrich

Pluto

unread,
Nov 6, 2009, 9:10:01 AM11/6/09
to
> Enrico- Hide quoted text -

>
> - Show quoted text -

> But watch your step: that \edef might do evil things.

Like what, please? I tried in vain to locate those devils.

Ulrich D i e z

unread,
Nov 9, 2009, 2:19:10 PM11/9/09
to
I wrote:

> %%---------------------------------------------------------------
> %% If _one_ \expandafter-chains hits
> %% \romannumeral\@expandtimes{N}<Argument> , then _N_ expandafter-
> %% chains will hit on the place of <Argument>
> %%...............................................................
> \newcommand\@expandtimes[1]{%
> 0\csname space\expandafter\@@@expandtimes
> \romannumeral\number\number#1 000D\endcsname
> }
> \newcommand\@@@expandtimes[1]{%
> \if#1m%
> \expandafter\expandafter\csname endcsname\expandafter\@@@expandtimes\fi}

If you used David Kastrup's \replicate-macro:

\def\recur#1{\csname rn#1\recur} \long\def\rnm#1{\endcsname{#1}#1}
\long\def\rn#1{}
\def\replicate#1{\csname rn\expandafter\recur
\romannumeral\number\number#1 000\endcsname\endcsname}

(see
http://www.gust.org.pl/projects/pearls/2005p/david-kastrup/bachotex2005-david-kastrup-pearl3.tex )
, you could easily as well implement it as follows:

\def\space{ }
\def\@expandtimes#1{%
0\csname space\replicate{#1}{\expandafter\expandafter\csname endcsname}\endcsname
}


Sincerely

Ulrich

0 new messages