Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

In the kernel the definition of protected@write includes the setting of the \thepage to \relax. Why is this and are there other means to ensure that thepage is not expanded?

\long\def \protected@write#1#2#3{%
     \begingroup
     \let\thepage\relax
     #2%
     \let\protect\@unexpandable@protect
     \edef\reserved@a{\write#1{#3}}%
     \reserved@a
     \endgroup
     \if@nobreak\ifvmode\nobreak\fi\fi
    }
share|improve this question
add comment

2 Answers

up vote 15 down vote accepted

Nice trick isn't it:-)

the \write doesn't happen until the page is shipped out in the output routine (it is not \immediate) so you want to \edef most macros so that they expand at this point while you know they are defined, otherwise the local environment might end, all the macros that are in the argument become undefined and you get undefined command errors during the \shipout. But the main reason for using a delayed write at all is so that page numbers fro cross references and the like get written out with the correct number which is only known at \shipout so you don't want that to expand early. So first do an \edef with \thepage set to \relax so it doesn't expand, then \write the result of that so \thepage can expand later in the output routine.

share|improve this answer
    
Nice trick indeed. There is also a nice follow-up trick by Kastrup in the perpage package where it imitates its behaviour for a custom counter -- takes a free ride into shipout:) –  Yiannis Lazarides Feb 18 '13 at 21:56
    
@YiannisLazarides yes the #2 in the definition you show is just a hook to allow other commands to get similar local definitions. –  David Carlisle Feb 18 '13 at 22:09
add comment

If it were expanded during \edef\reserved@a, it could have the wrong page number. Instead it is passed unexpanded inside \write, which will be executed during the next shipout operation, where it will expand to the correct value. At that time the redefinition to \relax will have been forgotten.

When a control sequence is equivalent to \relax it's left unchanged in an \edef operation (the same holds for any unexpandable token).

share|improve this answer
    
There would be other ways to avoid this (appropriate \noexpand, use of a toks, ...): I wonder if this particular approach saves a few tokens. –  Joseph Wright Feb 18 '13 at 21:34
    
@JosephWright It's not clear where you would put \noexpand or toks register use since you don't know where or if \thepage appears and you want to (protected0) expand everything else but thepage. –  David Carlisle Feb 18 '13 at 21:36
    
@DavidCarlisle I was thinking you'd set this up in the third argument to \protected@write, as you already do for other material to be protected from expansion (e.g. \string\newlabel). Untested, of course, and there are no comments in the code :-) –  Joseph Wright Feb 18 '13 at 21:38
    
@JosephWright One should remember to put \let\thepage\relax in the second argument every time \protected@write is used, if it were not part of the definition. –  egreg Feb 18 '13 at 21:40
    
@egreg Yes, that's in a way my point: \thepage is expandable, \protected@write is an \edef-like command so with my 'LaTeX3 hat' on I would not support the approach here for LaTeX3. However, I can see a token-saving argument in 1994 for this plan for LaTeX2e. –  Joseph Wright Feb 18 '13 at 21:42
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.