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.

Following the comments at Doing maths with distance values in LaTeX source code:

+1 for teaching me that \dimexpr can optionally swallow a \relax. Yesterday I tried to use \relax as a delimiter for \numexpr, and I just couldn't understand why the \relax is gone although it's not expandable. – Hendrik Vogt Feb 18 at 9:32

@Hendrik: Yeah, I think you need two \relax then. I find the \relax swallowing extremely useful. Its friends like \numexpr do the same. – Martin Scharrer♦ Feb 18 at 9:36

and with this issue being touched on again by the answers of Joseph and Martin at Which is better: a dimension or a macro?, I ask myself why does Etex do things this way? I find it unintuitive and I don't see how it can be useful to avoid carrying out a no-operation command.

share|improve this question
1  
Well, one alternative would be something like TeX' "keep on expanding until you find something you don't expect" semantics when parsing values, which is ... well, it's intuitive once you've gotten used to it. ;) –  Ulrich Schwarz Jun 10 '11 at 12:31
    
(I just left this as a comment on the original, but it could do with being here as well) Can we clarify that "optionally" in the first quoted sentence? Is it really optional? –  Loop Space Jun 10 '11 at 12:52
    
@Andrew: \dimexpr, etc. are terminated by the first token which cannot form part of an appropriate number. So something like a letter will terminate \numexpr without needing a \relax. So it is optional. –  Joseph Wright Jun 10 '11 at 13:26
    
@Joseph: It wasn't whether the \relax is optional but whether the swallowing was optional. –  Loop Space Jun 10 '11 at 14:33
2  
@Andrew: Ah, I see. In that case, it should perhaps read 'swallowing an optional \relax', as the swallowing itself is not optional. –  Joseph Wright Jun 10 '11 at 15:51
add comment

3 Answers

up vote 15 down vote accepted

To add to what Hendrik says, I think the overall point was that \numexpr, \dimexpr, etc. can be used in a full expansion context without leaving a stray \relax or space:

\edef\example{\the\dimexpr 10 pt + 20 pt \relax}

gives \example defined as 30pt with no unexpected tokens. That is in many ways much 'neater' than the alternative of leaving the \relax in place. The same argument does not apply to TeX's setting of registers as that is never expandable, so the issue does not arise.

(Of course, for a definitive answer you would need to ask the members of the NTS team who actually wrote this code.)

share|improve this answer
7  
IIRC, that was indeed one of the main reasons for doing it this way. –  Taco Hoekwater Jun 10 '11 at 14:11
    
It's the "much 'neater'" that I am having difficulties with. The expected semantics of \relax is to have a do nothing token survive the expansion process to be looked at and discarded by the backend. Etex would be faithful to this intuition if it took the \relax token from the input stream, did its work, and then put the token back. Then, for instance, a very experienced TeXnician like Hendrik would not have got into difficulty. How is this not neater? –  Charles Stewart Jun 11 '11 at 11:28
    
@Charles: 'Neater' is of course subjective. To me, it's neater that \example ends up as a length and nothing else, so I can compare a number I type in with one that is calculated (using two macros and \ifx). \relax is not itself part of the number, so to me should be 'tided up' inside an \edef. As I say, this is a subjective thing, and I certainly had nothing to do with writing e-TeX. –  Joseph Wright Jun 11 '11 at 14:10
add comment

I would say this makes it easy to delimit a \dimexpr in a fully expandable way. Putting a \relax is a usual way to delimit TeX dimensions, which I learned the hard way: It's always a good idea to put a \relax after something like \hskip1pt. Now it seems that eTeX just made a principle out of this.

(An alternative is to put a space to delimit a TeX dimension, but firstly a \relax is a lot more visible, and secondly it's sometimes not so easy to put a space, namely after a control sequence. As Bruno points out in his comment, spaces cannot be used to delimit \dimexpr and friends.)

share|improve this answer
3  
A space delimits a dimension, but cannot stop \dimexpr. One somewhat surprising case is \the\numexpr 1+2 3+4, which expands to 33+4: the number 2 is stopped by a space, and the 3 does not fit at that place in the \numexpr, which is thus stopped. A similar example can probably be built for \dimexpr. –  Bruno Le Floch Jun 10 '11 at 14:25
    
@Bruno: Thanks a lot for pointing this out! Is it better with my edit? –  Hendrik Vogt Jun 10 '11 at 15:46
    
yes, that's correct. –  Bruno Le Floch Jun 10 '11 at 17:16
add comment

For the same reason as TeX gobbles a trailing spaces from numbers. In the case of TeX, this is needed to stop a number cleanly and make sure that in all cases it will be terminated without expanding anything further nor inserting a blank space. In fact, TeX probably skips spaces after control words (multiletter control sequences) for the same reason (although that happens at a different stage of processing). The idea is that it should always be possible to "stop without inserting anything".

Example: \ifdigit below tests whether the argument is a digit. The space after #1 is required to stop TeX from expanding the first \expandafter prematurely. On the other hand, we don't want the space to end up in the output. So in that case at least, TeX's space gobbling is a feature.

\long\def\ifdigit#1{%
    \ifnum 9<1\string #1 %
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi}

eTeX's designers could decide that a space stops the \numexpr or \dimexpr, because they simply use TeX's procedures to read operands. And these procedures already remove a trailing space. eTeX does not see the space before + in \numexpr 1 + 2. It would have been technically possible to let \numexpr be stopped by two space tokens in a row, and gobble them, but that would be very difficult to input, since two space characters in a row are equivalent to one. Some other delimiter had to be chosen. It had to be non-expandable, preferably already there in the language, and it had better do nothing when used outside a \...expr situation... No need to add a new primitive: \relax was a natural choice.

Now consider a \compareint function defined as follows

\long\def\compareint#1#2#3{%
    \ifnum\numexpr#1\relax#2\numexpr#3\relax
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi}
\compareint{1+2}<{3-1}{Yes}{No}

In this particular case, leaving \relax behind would not be a problem. However, think of nesting this:

\def\X{345}\def\Y{534}
\compareint {132} < {\compareint{12}>{9}{\X}{\Y}+1} {Yes} {No}

If the \relax was not removed from the internal \compareint, it would stop expansion of the outside \compareint too early (actually, before expanding to \X or \Y, so that would be a problem).

share|improve this answer
    
In \compareint, you can miss out the first \relax as #1 will be terminated by the comparator #2. –  Joseph Wright Jun 10 '11 at 14:44
    
@Joseph: that's true. I hesitated when posting, but I think that putting \relax makes slightly clearer the fact that #2 is the comparison character. It also provides somewhat better error checking (against input like \compareint{1+2}{3}... where the user forgets the comparison). I should have said that this is taken directly from l3int (which doesn't have the first \relax). –  Bruno Le Floch Jun 10 '11 at 15:12
    
I know the relax is not in l3int, that's why I commented :-) –  Joseph Wright Jun 10 '11 at 15:15
    
@Joseph. I just did some speed comparison. On 10000000 \int_compare:nNnTF, I get 116 seconds both with and without the first \relax. So we may want to put it in l3int. I think the reason why it makes no speed difference is that in both cases two tokens are read. With \relax, \relax is read and swallowed, and then the comparison character, and without, the comparison character is seen, put back, and re-read. –  Bruno Le Floch Jun 10 '11 at 17:30
add comment

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.