10

I have a LaTeX problem and want to explain it with the following code snippet:

\documentclass{article}
\begin{document}

  \def\myline{A}
  \edef\myline{\myline \noexpand\bf B}
  \edef\myline{\myline C}

  \myline
\end{document}

I have to build up a line incrementally. This happens inside of a for loop. The problem is that I want to highlight some text in bold, but whenever I expand my line, I get the following error:

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.9 \myline

? X

I think, it is because of the third \edef, which tries to expand the \bf in the second \edef, however I have to expand it to avoid infinite recursion.

1
  • BTW: \bf is deprecated. Use either \bfseries or \textbf{<text>} instead. Commented Dec 23, 2011 at 15:58

3 Answers 3

10

Let's see what happens

\def\myline{A}
\edef\myline{\myline \noexpand\bf B}

Given the first line, the second is equivalent to

\def\myline{A\bf B}

Now, when you say

\edef\myline{\myline C}

TeX expands the inner \myline completely and this is what it becomes (result of \show\myline edited to avoid bad line breaks):

> \myline=macro:
->A\protect \protect \protect \edef OT1{OT1}\let \enc@update \relax
 \protect \edef cmr{cmr}\protect \edef m{m}\protect \edef n{n}
 \protect \xdef \OT1/cmr/m/n/10 {\OT1/cmr/m/n/10 }\OT1/cmr/m/n/10
 \size@update \enc@update \ignorespaces \relax \protect \relax 
 \protect \edef m{bx}\protect \xdef \OT1/cmr/m/n/10  
 {\OT1/cmr/m/n/10}\OT1/cmr/m/n/10 \size@update \enc@update BC.

which is surely not what TeX likes to see when executing the newly defined \myline.

The problem is that \noexpand inhibits expansion once: in the second \edef, the token \bf will be expanded. This is a "correct" way to proceed:

\documentclass{article}
\begin{document}

\makeatletter
\def\myline{A}
\protected@edef\myline{\myline \bfseries B}
\protected@edef\myline{\myline C}

\myline
\end{document}

Note that \protect in front of \bfseries is not needed, as \bfseries is already a "LaTeX robust command".

Another way is to use etoolbox:

\documentclass{article}
\usepackage{etoolbox}
\robustify\bfseries

\begin{document}

\def\myline{A}
\edef\myline{\myline \bfseries B}
\edef\myline{\myline C}

\myline
\end{document}

This will make \bfseries "protected forever" inside an \edef.

Martin suggests in his answer to use \appto, which is quite a good way to build a macro by accretion:

\usepackage{etoolbox}

\def\myline{}
\appto\myline{A \bfseries B}
\appto\myline{C}

In this case we get the same result as

\def\myline{A \bfseries BC}

If the accretion has to be global, you can use \gappto (which is equivalent to the kernel macro \g@addto@macro).

Another strategy is to use token registers:

\newtoks\mylinetoks

\mylinetoks={}
\mylinetoks={A \bfseries B}
\mylinetoks=\expandafter{\mylinetoks C}

Of course the register can be used as many times as one likes, it's necessary to allocate it only once. The kernel provides \addto@hook:

\newtoks\mylinetoks

\makeatletter
\mylinetoks={}
\addto@hook\mylinetoks{A \bfseries B}
\addto@hook\mylinetoks{\mylinetoks C}

For using the contents of the register, you say

\the\mylinetoks
0
7

As you said yourself \bf will be expanded by the second \edef. You need to add a \noexpand for this \edef as well, which has to be prefixed itself by a \noexpand:

\documentclass{article}
\begin{document}

  \def\myline{A}
  \edef\myline{\myline \noexpand\noexpand\noexpand\bf B}
  \edef\myline{\myline C}

  \myline
\end{document}

This of course gets out of hands fast if you have more \edef, especially if you don't now the exact number.

Better would be to use \protect and \protected@edef which makes sure that the \protect will stay independent of the number of expansions. In the normal text it then doesn't do anything, so it doesn't cause any trouble.

\documentclass{article}
\begin{document}

  \def\myline{A}
  \makeatletter
  \protected@edef\myline{\myline \protect\bf B}
  \protected@edef\myline{\myline C}
  \makeatother

  \myline
\end{document}

If you want to simple append material to \myline without expanding anything yet, you can use \expandafter:

\expandafter\def\expandafter\myline\expandafter{\myline <new stuff>}

So the old definition is expanded before it is defined again.

There is also a LaTeX macro \g@addto@macro\yourmacro{<stuff>} which adds stuff to the given macro, but however globally. It uses a token register (toks) for this.

The etoolbox package has some nice macros for this, like \appto\yourmacro{<stuff>} which works only locally.

2
  • You might also want to explain how to use a toks to achieve the same thing without the awkward \expandafter approach.
    – Joseph Wright
    Commented Dec 23, 2011 at 15:55
  • @JosephWright: I added the macro which use toks now. Not sure if you should explain exactly how they work. Commented Dec 23, 2011 at 15:59
4

As egreg noted, both \bf and \textbf are LaTeX protected. There is no need for \protect behind them in \protected@edef.

Maybe this is what Joseph Wright refers to:

\def\myline{A}
% \bfseries needs localization:
\@temptokena{{\bfseries B}}
\edef\myline{\myline \the\@temptokena}

The problem was that \protect became \relax when you made the definition. You could have done

% In document preamble:
\makeatletter
\@ifdefinable\protedef{\let\protedef\protected@edef}
\makeatother
% Subsequently:
\def\myline{A}
\protedef\myline{\myline {\bfseries B}}

Rather than load a package to robustify \bf or \bfseries, you can simply do

\newcommand*\mybf{} % \mybf is definable.
\let\mybf\bfseries
\protected\def\bfseries{\mybf}
\def\myline{A}
\edef\myline{\myline {\bfseries B}}

But this changes \bfseries globally, which (like \robustify) should only be done locally or within the document body.

In case you wonder how this doesn't lead to a cyclic definition, here is how it works in document body:

{\bfseries XX}

\bfseries->\mybf
\mybf->\protect\bfseries
{\relax}
\bfseries->\not@math@alphabet\bfseries\mathbf\fontseries\bfdefault\selectfont 

You must log in to answer this question.

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