How would you test whether we are in an expansion only context (i.e., \edef, \xdef, \write,...) or not? The only ways I could think of leave things behind (but the full expansion of that extra stuff is empty).

Is there a clean way of testing this?


We test that it sort of works: first, we are
\ifexpanding expanding\else not expanding\fi. 

Then, we are%
\edef\foo{\ifexpanding expanding\else not expanding\fi}
  • FWIW, my take on this was along the lines of \let\voodoo\voodoo with \voodoo starting with \relax\relax and ignoring its first argument, which does pretty much the same thing, but would leave a \let\relax\relax in an expanding context. (The whole story can be found in nag.dtx. Ah, the days we were young...) Jan 27 '11 at 9:16
  • @Ulrich: that's simpler than what I had! Although it has the same drawbacks, and in my case we obtain a protected but expandable command (if that makes sense). Jan 27 '11 at 10:07
  • @Bruno: yes, you're right. I admit to not having the required zen state to understand your solution right now. ;) Jan 27 '11 at 14:07
  • I'm curious, when would this come up?
    – TH.
    Jan 28 '11 at 2:45
  • 1
    @TH.: I am writing a package that reads a LaTeX source, and does TeXish macro replacements before rewriting itself to another file. For this, I replace each character by a macro, which should have two different behaviours depending on the expansion context. If it is running text in the source (i.e., typesetting, non-expanding), it should write the corresponding character to the output. If it is already in a \write, it should simply expand to the character. --- Since I have full control on what is going on, I can just keep track of things with a boolean, but I was lead to the question above. Jan 28 '11 at 7:14

I believe not, hence the addition of \ifincsname in pdfTeX (and XeTeX, I think). This came out of discussions way back when on detecting/testing all of the different expansion contexts, but IIRC the csname expansion was the only one that was easy or maybe unambiguous to implement.

Er, sorry for the vague answer; I'll pull up some references if they come to me.

  • 1
    Thanks. I'll leave the question open for a bit more, but I'm afraid that your answer is the right one. Although it is not clear why pdftex couldn't have a primitive for testing "if a protected sequence would expand there or not". Jan 27 '11 at 9:01

Short answer: no. Longer answer: To detect this would require a primitive which 'knows' about expansion. However, writing one is non-trivial: see the issues surrounding \ifincsname for demonstrations of why detection of this sort of thing is hard.

If you look at the LaTeX kernel, the \protect mechanism is about expansion. To work, it all has to be set up with \protect redefined correctly. That's why LaTeX2e 'robust' commands still require \protected@edef and similar to be used: within an \edef it is too late to alter anything.


Yes and no. My usual trick for this is this:


if I haven't gotten it wrong: in an expanding context, \let\voodoo\voodoo\RealStuff expands left-to-right to \let\relax\relax\Expansionstuff, continuing to expand \Expansionstuff since \let and \relax are primitive, but in either case, you are left with a reasonably non-harmful \let\x\x thingy.

  • So that's all inside the real macro, is that right? Sep 22 '11 at 13:02
  • However, this leaves your \edef or \write result containing extra tokens.
    – Joseph Wright
    Sep 22 '11 at 13:31
  • @Andrew: No, the \voodoo needs to be prepared in advance. Sep 22 '11 at 15:54
  • Okay, I'm having trouble seeing how it all fits together, but I haven't played with it yet. I'll have a go at trying it out and will get back to you. Sep 22 '11 at 17:31
  • 3
    @Andrew: Define \newcommand{\@ifexpanding}{\let\@ifexpanding@\@ifexpanding@\@secondoftwo} and \newcommand{\@ifexpanding@}[4]{\relax\relax#3}. You can then use it in macros as \@ifexpanding{<expandable code>}{<non-expandable code>}. Sep 22 '11 at 22:15

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.