[Tex/LaTex] How to use \noexpand in an \edef

expansion

Continuing with my struggle to deal with expansion issues, I am stuck on how to use an \edef properly. The code below with the switches set as:

%\def\ApplyColorToTitle{}
%\def\UseMathrmInTitle{}
\def\UseEdefInsteasOfDef{}

produces:

enter image description here

but as soon as I attempt to apply color formatting of the title, or even use \mathrm{} (surprisingly using \text{} does not exhibit this problem) in the title I get compile errors if I attempt to use the \edef. That is, the following settings work:

\def\ApplyColorToTitle{}
\def\UseMathrmInTitle{}
%\def\UseEdefInsteasOfDef{}

and produce the desired result:

enter image description here

However, I would like to be able to use this code with all the switches enabled:

\def\ApplyColorToTitle{}
\def\UseMathrmInTitle{}
\def\UseEdefInsteasOfDef{}

In this case I thought I needed to use a \noexpand on the formatting macro in the \edef:

\edef\FormattedTitle{\noexpand\FormatTitle{\Title}}

This \noexpand does work for the case of:

\def\ApplyColorToTitle{}
%\def\UseMathrmInTitle{}
\def\UseEdefInsteasOfDef{}

and hence I thought I was on the right track, but still fails with the use \mathrm{}.

Question:

How do I use the \edef instead of a \def and allow for use of \mathrm{} along with the color formatting?

Note:

  • I have to admit I am not sure why I have the \edef here in the first place, but there must have been a case that was not working that got fixed when I switched to using an \edef. I realize that it is not a very good reason, but that is why I would prefer to continue to use the \edef. If the expansion gurus here see no reason to be using an \edef here and recommend that I just use the \def I will do that until I am able to provide a MWE that actually requires a \edef.

  • I do need to use \mathrm{} instead of \text{} to ensure that the th is in roman font even if the title is wrapped in another formatting macro..

Code:

%\def\ApplyColorToTitle{}
%\def\UseMathrmInTitle{}
\def\UseEdefInsteasOfDef{}

\documentclass{article}
\usepackage{xcolor}
\usepackage{amsmath}

\newcommand*{\Title}{}%
\newcommand*{\SetTitle}[1]{%
    \renewcommand*{\Title}{#1}%
}%

\ifdefined\ApplyColorToTitle
    \newcommand{\FormatTitle}[1]{\textbf{\textcolor{blue}{\boldmath#1}}}%
\else
    \newcommand{\FormatTitle}[1]{#1}%
\fi


\begin{document}
\ifdefined\UseMathrmInTitle
    \SetTitle{$n^{\mathrm{th}}$ Root}%
\else
    \SetTitle{$n^{\text{th}}$ Root}%
\fi

\ifdefined\UseEdefInsteasOfDef% Would prefer to use an edef
    \edef\FormattedTitle{\FormatTitle{\Title}}%
    % Thought that adding this \noexpand would do the trick as
    % it seems to alow for \ApplyColorToTitle being defined.
    %\edef\FormattedTitle{\noexpand\FormatTitle{\Title}}%
\else
    \def\FormattedTitle{\FormatTitle{\Title}}%
\fi

Title is: \FormattedTitle
\end{document}

Best Answer

    \edef\FormattedTitle{\noexpand\FormatTitle{\noexpand\Title}}%

works but that's the same as not using \edef at all.

Basically the answer really is don't do that. \noexpand just stops one expansion occuring so you need exactly the right number of \noexpands depending on how many expansion contexts the token passes through. Too many and the token will finally act like \relax and do nothing. Not enough and things blow up.

The LaTeX \protect mechanism (or the e-tex protected primitive) is designed to avoid this, it holds tokens as if via \noexpand until you want to execute them. But this (for classic LaTeX protection) means using \protected@edef. Even with \protected@edef though you have to be careful not to suppress expansion of a command but allow its arguments to expand. If you do

\noexpand\FormatTitle{\Title}

then \FormatTitle expands to itself but \Title still expands as normal.


The error message you get from

\edef\x{\mathrm}

is quite obscure

! Undefined control sequence.
\GenericError  ...                                
                                                    #4  \errhelp \@err@     ...
l.6 \edef\x{\mathrm
                   }

It's quite entertaining (for some definition of entertainment) to see why, and what those ... are.

Let's start with an easier case.

If you try

\edef\x{\def\something{foo}}

You get the error

! Undefined control sequence.
l.7     \edef\x{\def\something
                              {foo}}

what is happening here is that to define x TeX goes along each token in the replacement text expanding every expandable token until the token is not expandable when it is added to the definition and the next token is expanded until you get to the closing }.

So the first token is \def. That is not expandable so is just added to teh definition of \x. the next token is \something which is intended to be the token defined by \def but that definition has not been executed, so the edef trues to expand \something and you get an undefined control sequence error (if the command is not defined).

If you first go

\let\something\relax

so \something is not expandable, then the initial edef does not generate an error and produces

> \x=macro:
->\def \something {foo}.
l.10 \show\x

So in the middle of the expansion of \mathrm there is a test and an error message in case the test fails, but in an edef the test doesn't really happen TeX just expands all the tokens anway so it ends up expanding \GenericError which has exactly the construct just described but with a slightly unusual control sequence whose name is

\@err@                                                                 %

that is, its name includes 65 space characters!

It turns out that this is the only token that is undefined so if you define this token you do not get an error:

\expandafter\let\csname @err@\space
\space\space\space\space\space\space\space\space\space\space\space\space
\space\space\space\space\space\space\space\space\space\space\space\space
\space\space\space\space\space\space\space\space\space\space\space\space
\space\space\space\space\space\space\space\space\space\space\space\space
\space\space\space\space\space\space\space\space\space\space\space\space
\space\space\space\space\endcsname
\relax

\edef\x{\mathrm}

\show\x

Produces:

> \x=macro:
->\protect \relax \protect \begingroup \immediate \write \@unused   \def \Messa
geBreak  
 \let \protect \edef\@err@                                                     
               You're in trouble here.  Try typing  <return>  to proceed.\Messa
geBreak If that doesn't work, type  X <return>  to quit.  \errhelp \@err@      
                                                            \let \@err@        
                                                          \def \MessageBreak  
                \def   \errmessage  LaTeX Error: \mathrm allowed only in math m
ode.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help\@err@                                     
                                \endgroup \relax .
l.18 \show\x

Note however that though the obscure error has gone, the defined command \x is completely useless. For example it contains

\let \protect \edef

which comes about as the original had an expansion like

\let \protect \string
 \edef....

but \edef has left \let \protect but \string has expanded converting the \edef token to the 5 character tokens \ e d e f so if executed the \let would define \protect to be let to a backslash character token.