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 obtain the expected result.
Merci
Pierre
\documentclass{article}
\makeatletter
\def\@nameedef#1{\expandafter\edef\csname#1\endcsname}
\def\foo#1{
\@nameedef{toto#1}{\bar}
> \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}
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}%
So what is the advantage of the chains of \expandafters over \edef.
You didn't say so. :)
> 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
>" \@namedef{totoa}{\bar}"
>" \expandafter\def\csname totoa\endcsname{\bar}"
>" \def\totoa{\bar}"
>
>(notice the space)
Why the space, please?
>> " \@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
>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
> But watch your step: that \edef might do evil things.
Like what, please? I tried in vain to locate those devils.
> %%---------------------------------------------------------------
> %% 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