11

Relax and exhale

I'm accustomed to seeing \relax at the end of many macros. Often, I don't understand the rationale; sometimes the placement seems more or less arbitrary to me.

For example, computing a math rubber length with stretch and shrink being the half of the modulus of the natural space goes like this (based on https://tex.stackexchange.com/a/669865):

\newcommand{\flexibleMSkip}[1]{%%% 50 per cent of the modulus of the argument after plus and minus. The argument may be any integer or floating-point number.
  \mskip#1
  plus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1\relax
  minus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1\relax
  \relax
}

This macro is so \relaxed that it's unlikely to ever need to unload to a psychiatrist. Technically, without the first \relax, the “minus” part is ignored, but why do we need the second and third \relaxes?

Now consider the same exercise for the text mode (my own creation):

\newcommand{\flexibleHSkip}[1]{%
  \hskip#1
  plus.5\dimexpr\ifdim #1<0pt -\fi#1
  minus.5\dimexpr\ifdim #1<0pt -\fi#1
}

This one seems not \relaxed at all but causes no stress to me on small examples. Here, putting a \relax at the end of the plus line or at the end of the minus line or at the end of the whole macro (just before }) causes no difference on my small examples. Would adding these \relaxes be necessary, or cause any joy or grievance, or would it, perhaps, speed up or slow down the computation?

You may claim that the exercise 27.4 from The TeXbook demonstrates the problem in general, but in our examples above, how can we possibly misconstruct the input to cause the occurrence of unintended meaning without error at compilation?

Here is a full, somewhat less \relaxed example for you to play with:

\documentclass{article}
%%% 50 per cent of the modulus of the argument after plus and minus. The argument may be any integer or floating-point number.
\newcommand{\flexibleMSkip}[1]{%
  \mskip#1
  plus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1\relax
  minus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1
}
\newcommand{\flexibleHSkip}[1]{%
  \hskip#1
  plus.5\dimexpr\ifdim #1<0pt -\fi#1
  minus.5\dimexpr\ifdim #1<0pt -\fi#1
}
\showoutput
\begin{document}
\(a\flexibleMSkip{-.5mu}b\)
c\flexibleHSkip{-.1em}d
\end{document}

And, by the way, in the plus and minus expressions, why do we multiply with .5 in the front rather than diving by 2 at the end? Does it make any difference?

  • Somewhat related: https://tex.stackexchange.com/questions/669361/problem-with-pagegoal as an example of problems caused by no \relax. – John Kormylo Jan 23 '23 at 20:52

1 Answers1

15

\relax is sometimes used as a generic non expandable token to stop scanning as in

\hsize=3in\relax

But here you are using e-tex expressions where \relax forms part of the syntax of the expression so unlike the above

\hsize=\dimexpr3in\relax

the \relax is consumed by the assignment and does not leave a \relax token in the stream.

so

\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1\relax

the final relax ends the (outer) \muexpr otherwise the minus at the start of the next line would form part of this expression.

Compare

\documentclass{article}
%%% 50 per cent of the modulus of the argument after plus and minus. The argument may be any integer or floating-point number.
\newcommand{\flexibleMSkipA}[1]{%
  \muskip0=#1
  plus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1\relax
  minus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1
  \showthe\muskip0
}

\newcommand{\flexibleMSkipB}[1]{% \muskip0=#1 plus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1 minus.5\muexpr\ifdim\mutoglue\muexpr#1<0pt -\fi#1 \showthe\muskip0 }

\flexibleMSkipA{1mu}

\flexibleMSkipB{1mu}

\stop

which shows removing the \relax changes the value

> 1.0mu plus 0.5mu minus 0.5mu.
\flexibleMSkipA ...0pt -\fi #1 \showthe \muskip 0

l.18 \flexibleMSkipA{1mu}

? > 1.0mu plus 0.5mu. \flexibleMSkipB ...0pt -\fi #1 \showthe \muskip 0

l.20 \flexibleMSkipB{1mu}

?



On your unrelated 2nd question prefixing with 0.5 is a classic tex <factor> and halves the natural length, discarding plus and minus components. /2 is e-tex division and halves all components.

\showthe\thickmuskip
\showthe\muexpr.5\thickmuskip\relax
\showthe\muexpr\thickmuskip/2\relax

produces

> 5.0mu plus 5.0mu.
> 2.5mu.
> 2.5mu plus 2.5mu.
David Carlisle
  • 757,742
  • Oh. Given what you wrote, it seems to me that in the first version of \flexibleMSkip with three \relaxes, the first two \relaxes are part of the syntax and the third \relax stops the scanning. Right? –  Jan 23 '23 at 19:57
  • @AlbertNash I added an example – David Carlisle Jan 23 '23 at 20:01
  • @AlbertNash \relax is not really part of the syntax (but it is good practice to use them in conjunction with \muexpr and friends), rather it stops \muexpr's scanning. \muexpr will stop scanning once it hits something invalid (something which isn't math glue), and \relax is such an invalid thing. But it's not always necessary as you've shown (also note the \muexprs in the \ifdims). So the first two \relaxes stop the scanning of \muexpr and the final \relax stops the scanning of \mskip. – Slurp Jan 23 '23 at 20:02
  • 1
    @Slurp Not really, as explained in the answer \relax is part of the syntax in the case of \muexpr, as the \muexpr does consume the \relax. – user202729 Jan 23 '23 at 20:04
  • 1
    @Slurp no for a classic assignment what you say is true but for \muexpr, \dimexpr etc an optional \relax is part of the expression syntax and is consumed unlike any other non expandable token which stops the scan but then is re-inserted. – David Carlisle Jan 23 '23 at 20:06
  • Yes you're both right, my comment was poorly worded (and not fully thought out). My main point was that the \relax isn't always necessary as OP was demonstrating in their question, but it is good practice to include – Slurp Jan 23 '23 at 20:08
  • Alright, thanks! How about \flexibleHSkip? Would we need, profit from, or suffer from \relaxes there? In other words, how does a \relax (inter)act with \dimexpr? –  Jan 23 '23 at 20:20
  • 1
    @AlbertNash \dimexpr is identical to \muexpr in all ways including \relax handling. the only difference is the units allowed. so your hskip example missing \relax is like my B example, it is error free but does not represent the length you intend – David Carlisle Jan 23 '23 at 20:25
  • 2
    @Slurp but the \relax in the OPs example are necessary, as my A and B examples show. If you miss them out you get no error but get the wrong length – David Carlisle Jan 23 '23 at 20:27
  • 1
    @AlbertNash I added a note re 0.5 and /2 – David Carlisle Jan 23 '23 at 20:35
  • @DavidCarlisle Oh, I see. So, do we better add \relaxes to \flexibleHSkip, too? Concerning multiplying by .5 vs dividing by 2: having values with stretch and shrink parts as arguments of \flexible{H|M}Skip makes no sense. The best outcome would be to throw an error (rather than silently discard) the parts in case the typesetter issues \flexibleHSkip or \flexibleMSkip with {… plus …} or {… minus …} as an argument. –  Jan 23 '23 at 20:46
  • @AlbertNash your hskip version is wrong (well assuming you want it to do what I think, like my B version it's valid tex but...) – David Carlisle Jan 23 '23 at 20:50
  • I see. I mean, let's say \newcommand{\flexibleHSkip}[1]{\hskip#1 plus\dimexpr\ifdim #1<0pt -\fi#1/2\relax minus\dimexpr\ifdim #1<0pt -\fi#1/2\relax\relax} or \newcommand{\flexibleHSkip}[1]{\hskip#1 plus.5\dimexpr\ifdim #1<0pt -\fi#1\relax minus.5\dimexpr\ifdim #1<0pt -\fi#1\relax\relax}. Both versions throw errors with plus or minus being a part of the argument. Any difference in the precision of multiplying .5 with the argument vs. dividing the argument by 2? –  Jan 23 '23 at 20:53
  • i'd use .5 form using /2 in that way is scary – David Carlisle Jan 23 '23 at 20:56
  • Purely mathematically, after partial evaluation, .5--1em is more scary to me than --1em/2, for example. –  Jan 23 '23 at 20:59
  • \ifdim #1<0pt -\fi#1 is intended to compute the modulus of #1. I thought that this is how the absolute value of a length is or should be computed in TeX, shouldn't it? –  Jan 23 '23 at 20:59
  • I thought that removing a bit of space but still leaving the possibility of slightly stretching and shrinking on need goes like this (say, in text mode): \hskip-1em plus.5em minus.5em. This way, if there is space left over on the line, TeX would remove between a bit less than 1em at the spot of the aforementioned command, and if the line is overcrowded, TeX would remove a bit more than 1em at the spot of the aforementioned command. (Here, I assume for simplicity that all the other stretches and shrinks on the line are nonnegative.) Am I wrong on this? –  Jan 23 '23 at 21:13