[There was an error in the first posted version: \twelverm instead of the first \tenrm in the statement \font\tenrm = \fontname\tenrm scaled 1200 The posting containing this correction is appended below.] Date: 27 Jan 1994 11:59:48 -0500 (EST) From: Michael Downes Subject: Around the Bend #16, answers To: info-tex@shsu.edu X-ListName: TeX-Related Network Discussion List Here is my commentary on Around the Bend #16. % \mag=1728 \hfuzz=1pt \tabskip=1pt \baselineskip=12pt % \topskip=10pt \lineskiplimit=1pt \lineskip=1pt % \mag=\time \ifnum\mag>1500 \T\else\F\fi % (1) (1): F --- At the time of the \ifnum, \mag is in the range [0,1440) depending on what time it was when you ran TeX. % \mag=\number\year \ifnum\mag>1500 \T\else\F\fi % (2) (2): F --- At the time of the \ifnum, \mag still has its previous value because TeX is still scanning for digits to add on after "1994". % \hfuzz=99pt \ifdim\hfuzz=99pt \T\else \F\fi % (3) (3): T --- Everything fine, dimension scanning terminated with the space after "99pt". % \tabskip=\z@ \ifdim\tabskip<\p@\T\else\F\fi % (4) (4): F --- \z@ is a dimension register, therefore it serves only as the first part of the glue value that TeX is looking for. At the time of the \ifdim, TeX is still looking for `plus' or `minus' and hasn't yet finished the assignment of \tabskip. % \tabskip=\p@ minus2pt \ifdim\tabskip>\z@\T\else\F\fi % (5) (5): T --- Glue value scanning terminated properly. \p@ is a dimension register like \z@ but the additional clause `minus 2pt' fills out the glue value to the required three parts. TeX assumes `plus 0pt' when it finds a `minus' clause without a preceding `plus' clause. Note that TeX does *not* continue scanning for a possible `plus' after reading a minus component. Unlike the height, depth, and width components of a \vrule or \hrule, the components of a glue value have a required order and each part can only occur once. % \baselineskip=-\prevdepth \ifdim\baselineskip=12pt \T\else\F\fi % (6) (6): T --- At the beginning of a vbox or at the beginning of a TeX run \prevdepth = -1000pt. So it would seem that \baselineskip should get set to +1000pt and the test should be False; but \prevdepth is a dimension register, not a glue register, so following stretch or shrink components are still possible, and \baselineskip does not yet have its new value at the time of the test. % \advance\baselineskip 2\topskip % (7) % \ifdim\baselineskip>\@m\p@ \T\else\F\fi % (7): F --- Without the factor 2 in front of \topskip, the test would be True: \topskip is a glue register so TeX would copy each component of \topskip to the corresponding component of \baselineskip; then, having plus and minus components already in hand, TeX would not scan ahead for `plus' or `minus'. However, a preceding factor for a glue register causes TeX to use only the first component of the glue register, multiplied by the given factor, which means that additional scanning is then attempted for possible stretch or shrink components. % \lineskiplimit=\z@ \ifnum\lineskiplimit>0 \T\else\F\fi % (8) (8): F --- Normal termination of dimension scanning. \lineskiplimit is a dimen register, not a glue register, so the dimen constant \z@ is sufficient to complete the assignment and TeX scans no further. % \lineskip=\z@skip \ifdim\lineskip>\lineskiplimit \T\else\F\fi % (9) (9): F --- Normal termination of glue scanning. \z@skip is a glue register so it suffices to complete the assignment of \lineskip. Compare to the \tabskip assignments above. % \kern2pc\ifdim\lastkern=2pc \T \else\F\fi % (10) (10): F --- At the time of the \ifdim, TeX is still looking for an optional final space at the end of the dimension value "2pc". If it were 2\p@ instead of 2pc, the test would evaluate to True. % \hskip1em % \ifvmode\T\else\ifdim\lastskip>\z@\msg{FT}\else\msg{FF}\fi\fi % (11) (11) FF --- TeX enters horizontal mode as soon as the \hskip command comes along, before it finishes scanning the skip amount. So the \ifvmode test is false. The \ifdim test is also false because scanning is not yet complete (TeX is looking ahead for a plus or minus component) so the glue has not yet been entered into the horizontal list, so it is not accessible to \lastskip. For more on the switch into horizontal mode, see `TeX from \indent to \par', Marek Ry{\'c}ko and Bogus{\l}aw Jackowski, TUGboat 14/3, October 1993 (1993 Annual Meeting Proceedings), pp. 171--176. % \font\cmrtest=cmr10 \ifx\cmrtest\tenrm \T\else\F\fi % (12) (12) F --- Interestingly, the following versions of the \ifx test are also false at that point: \ifx\cmrtest\undefined, \ifx\cmrtest\relax. The reason is that after "\font\cmrtest" TeX immediately sets \cmrtest = \nullfont, before scanning the rest of the font assignment. So the test \ifx\cmrtest\nullfont would yield True. According to the TeXbook, the reason for this behavior is to allow statements of the form \font\cmrtest=cmr10 \cmrtest for switching to the font \cmrtest immediately after it is defined. TeX does a bit of boomeranging in such a case: \font\cmrtest % set \cmrtest = \nullfont =cmr10 % space terminates font name, start looking for % "at" or "scaled" \cmrtest % \cmrtest = \nullfont = nonexpandable, not % "a", not "s"; terminate the font assignment % and put back the \cmrtest token to be read % again: \cmrtest % Now \cmrtest selects the given font Although I sympathize with Knuth's desire to smooth out a potential problem for naive users, I wonder if it only encourages users to pay less attention to the nitty-gritty details of scanning and expansion, and therefore lay themselves open to greater confusion later on when something similar fails (inconsistently!) to work. I'd have thought it better to require, and document, proper termination of font assignment scanning by \relax or whatever. Users would have to be a little more knowledgeable but they would be rewarded with a more consistent language to work with. As it stands TeX unnaturally forbids certain constructions that are perfectly colloquial to anyone who has an ear for the TeX language, such as \font\tenrm = \fontname\tenrm\space scaled 1200 I hold a similar opinion for the way \chardef and \mathchardef set their arguments to \relax before scanning the number on the right-hand-side of the assignment. Occasionally I would *like* to be able to write something like \chardef\foo=\ifcase\foo 1\or 2\else 3\fi, but TeX doesn't allow that. One could argue that the \chardef behavior should for consistency be imitated by \edef, \xdef so that if \foo is undefined then \edef\foo{a\foo} should not give an undefined control-sequence error for the \foo in the replacement text, but make it temporarily equivalent to \relax and leave it there. (Of course, this means that executing \foo will then start up an infinite loop, but my point was that it's the behavior of \chardef that should be changed to achieve consistency, not the behavior of \edef.) ======================================================================== At the end of Exercise #16 there was the question `Where should \relax should be inserted?' \relax should be inserted just before the \if... in statements (2), (6), (7), (11), and (12). In statement (4) \z@skip should be used instead of \z@; then \relax is unnecessary. A space suffices instead of \relax in (10). I would also tend to put a \relax at the end of the preliminary assignments to \baselineskip and \lineskip, as a matter of principle; I like to make sure that scanning is definitely terminated at the end of a line, so that if any error occurs during the scanning, TeX will show the line containing the assignment statement and not a later line. This is particularly relevant for font assignments: If foo10.tfm does not exist on your system, then the assignment \font\foo=foo10 will cause TeX to show you the blank line instead of the preceding line in the error context: ! Font \foo=foo10 not loadable: Metric (TFM) file not found. \par l.2 And if the following material is some complicated macro instead of a blank line, TeX will go into the replacement text of the macro, looking for "at" or "scaled", before giving the error message! Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Date: 28 Jan 1994 08:01:12 -0500 (EST) From: Michael Downes Subject: Around the Bend #16, answers, correction To: info-tex@shsu.edu Instead of \font\twelverm = \fontname\tenrm\space scaled 1200 read \font\tenrm = \fontname\tenrm\space scaled 1200 The latter line is what I originally wrote but I changed it in an obtuse moment a day later, forgetting the very point it was supposed to illustrate.