29

Can two macros - with the same body, so that comparison with \ifx would be true - have different behaviour depending on their name?

\documentclass{article}
\newcommand\red{some code for: if my name is red "red" else "not red" fi}
\let\blue\red
\begin{document}
\ifx\red\blue true \else false \fi %must give true
\red  %prints red
\blue %prints not red
\end{document}

I think the answer is no, but perhaps there is some trick I'm not aware of. Answers which work only for some engines are ok.

  • Does this redefined problem bear any relation to your interest, or not at all? \documentclass{article} \begin{document} \makeatletter \newcommand\testR[1]{\expandafter\if\expandafter\@gobble\string#1\R R\else Not R\fi} \def\R{R} \let\B\R \ifx\R\B true\else false\fi\par \testR\R\par \testR\B \end{document} – Steven B. Segletes Nov 9 '18 at 20:03
  • @StevenB.Segletes no that's not my question. You use an outer macro \testR to check the name -- that is rather easy, I wanted to know if \R itself knows its name. – Ulrike Fischer Nov 9 '18 at 20:19
  • I figger'ed. Just checkin' – Steven B. Segletes Nov 9 '18 at 20:27
  • would LuaTeX not be able to do this with some macro pre-processing? – user89 Nov 10 '18 at 4:15
31

No. The macro must be expanded to reveal and execute the code. But the expansion replaces the macro token with the definition text, meaning the original macro is gone and no trace* is left that shows, where the code has come from.

* If \tracingmacros is active, then the .log file would tell the expansion step, but enabling \tracingmacros in the macro itself is too late. Also reading the .log file from within TeX is not as easy because the .log file block might not yet be written (buffered output/OS dependent behavior/...) and in the second run the .log file will be overwritten.

21

I don't know the origin of this question (two macros are the same from \ifx point of view and behaves differently with respect of their name). But I would to present the way to modification of TeX source to solve this task. I don't expect that somebody use this patch. This is only an illustration how easy or hard such modification is. Let me start by citation:

Certainly, if I were in the publishing business myself, I would have probably had ten different versions of TEX by now for ten different complicated projects that had come in. They would all look almost the same as TEX, but no one else would have this program--they wouldn't need it, they're not doing exactly the book that my publishing house was doing.

Donald E. Knuth, Prague, March 1996

We need to add the new primitive \lastexpanded which expands to the name of the last expanded macro similar as \string does it. This means, that

\TeX \edef\a{\lastexpanded}  \edef\b{\string\TeX}
now: \a is equal to \b

We do this by creating mytex.ch change file. This is a "patch" to the tex.web source file. We start by intensively flipping through second volume of C&T (TeX: The program) and by intensively thinking about it. Then we create the following file:


% This is a modification of TeX inspired by
% http://tex.stackexchange.com/questions/130285/has-a-command-access-to-its-own-name
% This modification adds new primitive \lastexpanded which expands to the
% \string of the last expanded macro name.

\S 297 declaration of global variables
@x
@!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|}
@y
@!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|}
@!lastexpanded_cs: pointer; {variable for \.{\\lastexpanded}}   
@!lastexpanded_chr: halfword; {|cur_chr| for \.{\\lastexpanded}}
@z

\S 389 macro_call saves its name
@x
warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0;
@y
warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0;  
lastexpanded_cs:=cur_cs; lastexpanded_chr:=cur_chr;
@z

\S 439 default values
@x
cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal;
@y
cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal;
lastexpanded_cs:=0; lastexpanded_chr:=0;
@z


\S 468 adding new expandable primitive \lastexpanded
@x 
@d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}}
@y
@d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}}
@d lastexpanded_code=pdftex_convert_codes + 1 {command code for
\.{\\lastexpanded}}
@z

@x
primitive("jobname",convert,job_name_code);@/
@!@:job_name_}{\.{\\jobname} primitive@>
@y
primitive("jobname",convert,job_name_code);@/
@!@:job_name_}{\.{\\jobname} primitive@>
primitive("lastexpanded",convert,lastexpanded_code);@/
@!@:lastexpanded_}{\.{\\lastexpanded} primitive@>
@z

\S 469 printing about new primitive
@x
  othercases print_esc("jobname")
@y
  lastexpanded_code:   print_esc("lastexpanded");
  othercases print_esc("jobname")
@z

\S 470 the c declaration
@x
@!c:number_code..job_name_code; {desired type of conversion}
@y
@!c:number_code..lastexpanded_code; {desired type of conversion}
@z

\S 471 Scanning argument, \lastexpanded has no argument
@x
job_name_code: if job_name=0 then open_log_file;
@y
job_name_code: if job_name=0 then open_log_file;
lastexpanded_code:  do_nothing;
@z

\S 472
@x
job_name_code: print(job_name);
@y
job_name_code: print(job_name);
lastexpanded_code: if lastexpanded_cs<>0 then sprint_cs(lastexpanded_cs)
  else print_char(lastexpanded_chr);
@z

The new expandable primitive is added in section 468. Here is a little complication because our patch will be applied to the pdftex: there are many new primitives and this is a reason why there is different value of the last code job_name_code than in the original TeX. The global variables lastexpanded_cs and lastexpanded_chr are set in macro_call procedure (section 389) and they are used in section 472 when \lastexpanded is expanded.

Now, you can add the mytex.ch as the last item to the pdftex_ch_srcs list in the Makefile in the source/build/texk/web2c/ of the pdftex source. Then you can run make pdftex. The new pdftex binary is compiled. You can try:

 ./pdftex -ini
 **\relax
 *\show\lastexpanded
 > \lastexpanded=\lastexpanded.

You can generate the format ./pdftex -ini -jobname pdftex -etex pdfetex.ini and use it in the same directory by ./pdftex test. The test.tex would be:

\edef\redname{\string\red}
\def\red{\edef\myname{\lastexpanded}%
    \ifx\myname\redname \message{I am RED}%
    \else  \message{I am NOT red}%
    \fi
}

\let\foo=\red

\red   % the output:  I am RED
\foo   % the output:  I am NOT red

\ifx\red\foo \message{YES}\fi   % the otput: YES

\end
  • 3
    ooh this patch is awesome! :) – Paulo Cereda Aug 14 '14 at 10:25
  • Let’s start a campaign for having this primitive introduced in pdfTeX (edit: all typesetting engines)! :-D I think that a better name would be \lastexpandedmacroname, though. – GuM Nov 9 '18 at 19:20
3

Also as Heiko has said, it is not possible to do that using a macro by itself, I think it might be possible to do this using something that looks like a macro but is not.

The mean i think of would be do decide of a prefix character that would be applied to every color, and make this to be active. You would then be able to gobble the tokens of the color name from within that active character and do what you described.

For exemple, using "/" as the active character, you would then declare your color using

/red  % Gives "red"
/blue % Gives "not red" 
  • If it isn't a real macro the \ifx-test will fail. Also the colors in my example were only for demonstration, in my actual problem I was investigating if I can tweak the behaviour of beamer in ignorenonframetext mode. – Ulrike Fischer Aug 28 '13 at 14:49
  • Hum, if you are specifically wanting to tweak something already existing, this sure couldn't help. Maybe you should insist a litle bit more on this constraint in your question. Also, i'm not really sure of what to do in that kind of case ... should I delete my answer ? – Samuel Albert Aug 28 '13 at 15:50

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.