11

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}
5
  • 3
    Never use \edef on tokens like \mathrm: they do assignments which are not performed in \edef. Rather use \protected@edef. (And never use superscripted "th", please.)
    – egreg
    Commented Jul 4, 2012 at 21:56
  • @egreg: Yep that sure seems to work just fine... Thanks. Should I just use \protected@edef all the time? Commented Jul 4, 2012 at 22:00
  • I don't see any reason why you'd want \edef (or variants thereof) in this case. But the answer is no: \protected@edef and \edef are different.
    – egreg
    Commented Jul 4, 2012 at 22:01
  • Don't forget the macro \textup.
    – Mico
    Commented Jul 5, 2012 at 1:05
  • @Mico: Yep that too works, but I have already changed all my code to use \def, but thanks for the suggestion. Commented Jul 5, 2012 at 1:12

2 Answers 2

11
    \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.

2
  • I was trying to expand \Title, as the \FormatTitle does not change. Perhaps that is not the right logic for expansion, but that was my thinking. Commented Jul 4, 2012 at 22:03
  • 3
    but expand it to what? If you just expand it once you'd get $n^{\mathrm{th}}$ Root but edef expand until there is nothing left to expand and \mathrm is trying to set fonts, potentially dynamically load fonts for the current size, and generally do stuff doing stuff in an edef doesn't work:-) Commented Jul 4, 2012 at 22:06
9

Let's see what happens when all three of your first definitions are set:

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

\newcommand{\FormatTitle}[1]{\textbf{\textcolor{blue}{\boldmath#1}}}
\SetTitle{$n^{\mathrm{th}}$ Root}

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

\edef causes the expansion of \FormatTitle first, so at the first stage we get

\textbf{\textcolor{blue}{\boldmath\Title}}

Now \textbf is expanded, which gives \protect\textbf• (the bullet denotes a space in the macro's name). At this time \protect is equivalent to \relax which is put aside, being unexpandable and the expansion proceeds with \textbf•, giving

\ifmmode\nfss@text{\bfseries#1}\else\hmode@bgroup\text@command{#1}\bfseries\check@icl#1\check@icr\expandafter\egroup\fi

(where #1 is really \textcolor{blue}{\boldmath\Title}). We're not in math mode, so the next token to be expanded is \text@command, which starts with \def\reserved@a: oh, boy!, the next token to be expanded is \reserved@a which has a completely unpredictable value. It's a temporary control sequence often used in the LaTeX kernel and it's wrong trying to expand it here because we'd really want to give it a new meaning, which is not possible during an \edef.

Let's change and use \protected@edef

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

\newcommand{\FormatTitle}[1]{\textbf{\textcolor{blue}{\boldmath#1}}}
\SetTitle{$n^{\mathrm{th}}$ Root}

\makeatletter
\protected@edef\FormattedTitle{\FormatTitle{\Title}}
\makeatother

I don't want to do all steps; but \protected@edef changes the meaning of \protect so that the expansion of \FormattedTitle becomes

\protect\textbf•{\protect\leavevmode{\protect\color•{blue}\relax\protect\mathversion•{bold}$n^{\protect\mathrm•{th}}$ Root}}

(again the bullet denotes spaces in the control sequence names).

It's easy to see that \protected@edef does nothing sensible in this case. Indeed, if the simple \def is used, the code would be

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

\newcommand{\FormatTitle}[1]{\textbf{\textcolor{blue}{\boldmath#1}}}
\SetTitle{$n^{\mathrm{th}}$ Root}

\def\FormattedTitle{\FormatTitle{\Title}}

and calling \FormattedTitle would do exactly what you want without any hassle.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .