17

Here's an example of some code from LaTeX's \DeclareFontFamily:

\def\reserved@a{#3}
\global
\expandafter\let\csname #1+#2\expandafter\endcsname
       \ifx \reserved@a\@empty
         \@empty
       \else \reserved@a
       \fi

I could be wrong, but to me this looks identical to:

\expandafter\gdef\csname#1+#2\endcsname{#3}

Now, the source for this code comments:

We compare \reserved@a with \@empty If these two are the same we \let the ‘extra’ macro equal to \@empty which is not the same a doing a \let to \reserved@a — the latter would blow one extra memory location rather then reusing the one from \@empty.

But if we're not re-using the contents of \reserved@a after this point (which we're not, as far as I can see), there's no reason to go this roundabout route, right?

1 Answers1

13

For a full answer you'd need to ask one of the people who might have written this (possible Frank Mittelbach or even Leslie Lamport - I wonder if this has come all the way from 2.09). However, what I think is happening is that when \reserved@a is not equal to \@empty then there is no saving, as at some later stage \reserved@a will be needed again. On the other hand, when \reserved@a is equal to \@empty then a memory position is saved, as \@empty never changes and so the two macros always have the same definition as each other. When this code was written, such small savings were probably really important (they all add up).

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
  • 1
    Do I read that correctly that TeX uses some form of copy-on-write with macros defined using \let? This is very interesting. – Martin Scharrer Feb 23 '11 at 09:37
  • 6
    @Martin: Macros \let to each other have only one definition in memory (the hash table entries point to the same definition), whereas \def creates independent definitions even if the two are identical. – Joseph Wright Feb 23 '11 at 10:06
  • I think I now have an alternative explanation: \def\a{}\def\b{} takes more (or twice as much) memory as \def\a{}\let\b\a. (I still think \reserved@a isn't reused.) Hence my first suggestion wouldn't be a good idea (back then when memory was scarce). WDYT? More importantly, does it matter these days? – Will Robertson Feb 23 '11 at 13:33
  • @Will: That's what I've tried to say - \reserved@a isn't the key here, it's the \@empty branch that does the saving. I'd say today it doesn't matter at all: one of the problems with the current kernel is that these tricks make maintenance much harder. – Joseph Wright Feb 23 '11 at 13:37
  • @Will. Isn't \reserved@a used in e.g. environments, and everywhere in LaTeX? – Bruno Le Floch Feb 23 '11 at 13:41
  • @Bruno — \reserved@a (and @b, etc.) are scratch registers used in the kernel and assumed not to interact with any other code (unlike \@tempa and so on). – Will Robertson Feb 23 '11 at 14:02
  • @Joseph — Oops, yes, now I see how you intended that to come across. A bit slow tonight, I'm afraid. Thanks! (It occurs to me that we could have a function \cs_set_eq_probably_empty:NN that incorporates this test but I really don't think it's worth it.) – Will Robertson Feb 23 '11 at 14:05
  • @Will: I was commenting on I still think \reserved@a isn't reused: it is reused all over the place, so you're not wasting any memory cell, since that definition would be cleared whenever \reserved@a is redefined. – Bruno Le Floch Feb 23 '11 at 14:38
  • @Bruno — oh, we misunderstood each other. I meant to say that ‘the contents of \reserved@a’ aren't reused. Hence why save the argument to a macro in the first place? But Joseph answered that question now. Thanks :) – Will Robertson Feb 23 '11 at 14:43