3

Sometimes, I want to redefine some cs in a range, generally a macro definition. Like:

 \def [[csname>]] { [[Redefine some cs]] [[Actual function of this macro]] [[Recover the redefined cs]] } 

What mainly needed to do is define macros of Redefine and Recover, let's call them \redefine and \recover.

For recovering, a hardly conflict cs should be used to store the meaning of cs to be redefined, and their names should be relative. Here I use "the csname of its csname" :

\def\redefine#1#2{ \expandafter \let \csname\string#1\endcsname #1 \relax \def#1{#2} } 

Where #1 is the cs to be redefined.

Now I found that the original meaning can not be recover.

\def\recover#1{ \let #1 \csname\string#1\endcsname } 

It seems that \csname\string#1\endcsname can not be expanded before \let, because # 1 are two different tokens but treated as argument replacement in macro definition iff they successively appear. Meanwhile \expandafter just skip 1 token.

Maybe \def but not \let can be used in most cases, I still want to know any way to make the 2nd token be expanded before the 1st when the 1st token is an argument?


i.e.

Some shorter primitive cs are defined:

\let\epaf\expandafter \let\str\string \let\nep\noexpand \let\cs\csname \let\sc\endcsname ... 

for a macro named \mfont that parse a sentence until \relax, and set lots of font attribute, and make a single cs set latin font and unicode font at the same time. It use lots of primitive cs to parse sentence, definiiton is hard to read if keep the long name.

After a block from \mfont to \relax , shoter names should be recovered. \mfont should define font for global but the shorter names should be valid just in the \mfont range.

13
  • 1
    Can't you just use grouping? I mean: \begingroup ... \def\cs{whatever} ... \endgroup? Commented May 26, 2023 at 15:47
  • 1
    You have abstracted the question well, but IMHO if you posit the question in context with a real-world application, you might get better answers and methods of achieving what you want. (x-y problem) Commented May 26, 2023 at 15:55
  • 1
    Sorry, but your explanation is still not very clear. It still looks like what you are saying can be achieved with grouping. Commented May 26, 2023 at 16:02
  • 1
    Try this: \def\bar{foo} \def\foo#1{\begingroup\def\bar{#1}\endgroup}\foo{bar}\bar\par \def\foo#1{\begingroup\gdef\bar{#1}\endgroup}\foo{bar}\bar \bye Commented May 26, 2023 at 16:07
  • 1
    Ah, but if you \global\def, then grouping does not work, clearly. But you didn't mention it in the question... 😉 Commented May 26, 2023 at 16:18

3 Answers 3

4

enter image description here

You had spurious spaces, and missing \expandafter

% no space!!!! \def\redefine#1#2{% \expandafter \let \csname\string#1\endcsname #1% \def#1{#2}% } % no space!!!! \def\recover#1{% % missing \expandafter \expandafter \let \expandafter #1\csname\string#1\endcsname } {\tt \string\sin=\meaning\sin} \redefine\sin{hello} {\tt \string\sin=\meaning\sin} \recover\sin {\tt \string\sin=\meaning\sin} \bye 
3
  • Thanks! It seems that I just don't aware that \expandafter can work exactly next to another \expandafter. And I tried \def\stringstring#1{\expandafter\string\csname\string#1\endcsname} \def\cscs#1{\expandafter\if\stringstring#1\else#1\fi} , this can make \expandafter\let\csname\cscs#1\expandafter\endcsname\csname\string#1\endcsname works. Commented May 26, 2023 at 17:11
  • @rikuri the \expandafter in \cscs is doing nothing there Commented May 26, 2023 at 17:18
  • Yes, according to texbook \if will totally expand conditions, thanks for comment! Commented May 26, 2023 at 17:24
3

Besides spurious spaces, your code for \recover does

\let #1 \csname\string#1\endcsname 

If you call \recover\foo you get

\let\foo\csname\string\foo\endcsname 

so you are redefining \foo to be \csname, printing \foo (as a string) and get an error message about a badly placed \endcsname.

You need

\expandafter\let\expandafter#1\csname\string#1\endcsname 

so the token is formed before \let starts to act.

Alternative method where you need not worry about spurious spaces and \expandafter.

The c argument type means “form a control sequence token” (it uses \csname...\endcsname internally and applies the correct \expandafter sequence. Also \cs_set:Npn is the equivalent of \def (actually \long\def, but it's unimportant in this context).

\input expl3-generic \ExplSyntaxOn \cs_new_protected:Npn \redefine #1 #2 { % save the current meaning of #1 \cs_set_eq:cN { \token_to_str:N #1 } #1 \cs_set:Npn #1 { #2 } } \cs_new_protected:Npn \recover #1 { \cs_set_eq:Nc #1 { \token_to_str:N #1 } } \ExplSyntaxOff {\tt \string\sin=\meaning\sin} \redefine\sin{hello} {\tt \string\sin=\meaning\sin} \recover\sin {\tt \string\sin=\meaning\sin} \bye 

enter image description here

If you don't want to go this route, you can and should define your own syntactic sugar. But expl3 offers you much more than \cs_set_eq:NN and variants thereof.

\def\cslet#1{\expandafter\let\csname#1\endcsname} \def\letcs#1#2{\expandafter\let\expandafter#1\csname#2\endcsname} \def\redefine#1#2{% % save the current meaning of #1 \cslet{\string#1}#1% % redefine #1 \def#1{#2}% } \def\recover#1{\letcs#1{\string#1}} {\tt \string\sin=\meaning\sin} \redefine\sin{hello} {\tt \string\sin=\meaning\sin} \recover\sin {\tt \string\sin=\meaning\sin} \bye 
2

For the sake of coping with implicit space when doing \let I suggest s.th. like this:

\def\redefine#1{% \expandafter\futurelet\csname\string#1\endcsname\def#1% }% \def\exchange#1#2{#2#1}% \def\recover#1{% \expandafter\exchange\expandafter{\csname\string#1\endcsname}{\let#1= }% }% \def\foobar{foo} \foobar \redefine\foobar{bar} \foobar \recover\foobar \foobar \bigskip Doing the implicit space game: \bigskip \exchange{ }{\let\foobar= }% A\foobar A \redefine\foobar{bar} B\foobar B \recover\foobar C\foobar C \bye 

enter image description here

Alternatively just do some scoping via \begingroup..\endgroup or {..}:

\def\foobar{foo}% \foobar \begingroup \def\foobar{bar}% \foobar \endgroup \foobar {% \def\foobar{bar}% \foobar }% \foobar \bye 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.