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.

I find it annoying that using \csname...\endcsname will define ... to be \relax if ... is undefined, and there is no improved primitive that does not have this side-effect, though there are partial workarounds (as previously asked in another question).

I may be wrong, but I'm currently thinking that the only use of the \relax side-effect was for testing if a command was undefined before the days of e-TeX and \ifdefined. Obviously, we'll probably be stuck with this side-effect now as there will be lots of code that relies on it, but is anyone aware of any other uses for the side-effect? Might one day another primitive be introduced that doesn't have this side-effect?


Post-acceptance update:

(Many thanks for all the answers and comments, I've learnt something from each and so I'm glad I asked this question!)

Note that I've accepted Bruno's answer as he has been able to show me some good uses of the side-effect. If you're coming to this question late, you may find it clearer to read the answers in chronological order (David's, Joseph's then Bruno's). Also, I'm still interested in any other uses that you discover/remember/invent or if anyone can say with more certainty what the original intention was.

Summary (with apologies if I'm doing a bad job, feel free to edit or remove):

  • The overall feeling is that the side-effect is not a bad thing;
  • David pointed out that the side-effect wasn't necessary to be able to have a pre-eTeX \ifdefined test;
  • Joseph (and Frank) mentioned memory and performance issues, and showed that the side-effect was clearly an intentional design decision, though the reason for the decision isn't specified in the tex.web source;
  • Bruno showed three very clever uses of the side-effect and further increased my excitement about LaTeX3!
share|improve this question
2  
If \csname ...\endcsname did not leave things as \relax, what would the construct give? This is used for example by LaTeX's \end{...}, where you don't have to have a definition for the \end<foo> macro for an environment to work. –  Joseph Wright Aug 10 '12 at 21:16
    
@JosephWright: thanks, another point I hadn't considered. It's great to know that the side-effect has found a use and so perhaps isn't as much of a pain as I previously thought. But surely the side-effect pre-dates LaTeX, so I also wonder what the original intentions for its use were? –  cyberSingularity Aug 10 '12 at 22:31
    
My thinking was that it would leave things as undefined. (This construct seems to be odd in that it defines a control sequence expandably, albeit to something of limited use, which then cannot be undone in the same way, except by leaving an enclosing group.) –  cyberSingularity Aug 10 '12 at 22:38
    
Of course, LaTeX's \end{...} could be defined to first check if the \end<foo> macro exists before attempting to invoke it (and if not, then just do nothing), and so this isn't such a make-or-break issue. –  cyberSingularity Aug 10 '12 at 22:46
1  
I'm fairly certain this was a concious design decision by Don and a side-effect that just happened and then got documented. Thus "improved primitive" may be the wrong wording here ... more primitive with different behavior. There is no written proof that I know of but my bet is on a speed decision for the most likely use case: generate + execute (and do nothing if undefined). –  Frank Mittelbach Aug 11 '12 at 20:24
show 1 more comment

3 Answers 3

up vote 14 down vote accepted

I've used the \relax side-effect of \csname ...\endcsname for three purposes.

The first

is similar to how LaTeX uses it in \end{...}. Let's call TeXu a variant of TeX in which \csname ...\endcsname leaves undefined control sequences undefined.

We have a list of keys, and associated actions (arbitrary TeX code), and we want to define \act{#1} to do the action labelled by the key #1. First define the various actions.

\def\actA{\message{I found A.}}
\def\actB{\message{Oh, here is a B!}}
\def\actKEY{\message{The key was KEY.}}

If you want \act to produce no error on undefined keys, you would do

% in TeX
\def\act#1{\csname act#1\endcsname}
% in TeXu
\def\act#1%
  {%
    \expandafter\ifx\csname act#1\endcsname\undefined
    \else
      \csname act#1\expandafter\endcsname
    \fi
  }

Now, you could argue that having an error would be better, since we'd want to catch typos in key names. So how do TeX and TeXu compare in that case? Well, \def\act#1{\csname #1\endcsname} would work in TeXu. However, is Undefined control sequence \abcKEYZ really the best error message? For a better error message, we can do

% in TeX
\def\act#1%
  {%
    \expandafter\ifx\csname act#1\endcsname\relax
      \errmessage{Unknwon key #1}%
    \else
      \csname act#1\expandafter\endcsname
    \fi
  }
% in TeXu, same, with `\relax` replaced by `\undefined`.

However, with TeX we can do something slightly faster:

% in TeX
\def\actA#1#2{\message{I found A.}}
\def\actB#1#2{\message{Oh, here is a B!}}
\def\actKEY#1#2{\message{The key was KEY.}}
\def\act#1%
  {%
    \csname act#1\endcsname
      \errmessage{Unknown key #1}%
  }

If the key is known, the \act... function removes the error message, and if it is unknown, the undefined \csname construction turns into \relax, and an error message is displayed. There is no equivalent for TeXu. At the time of writing, this construction is used in l3kernel for \prg_new_conditional:Npnn and related functions (where valid keys are the conditional forms T, F, TF, and p), and for \int_compare:nTF (where valid keys are the comparison operators <, =, >).

The second

is for reporting special conditionas in an expandable setting. I use this in the LaTeX3 floating point module l3fp (found in the l3kernel bundle), and in the string conversions in l3str (in the l3experimental bundle).

Let's look at l3fp. \fp_to_tl:n {#1} evaluates the floating point expression #1 and turns it into a list of tokens (such as 0.123 or -1.4e-789 or -inf), expandably. When plotting graphs, for instance, we want \fp_to_tl:n { 1/0 } to simply give inf, but in other contexts this should trigger an error. I've recently added an experimental feature (not fully implemented) where one can test if a division by zero or another special condition occurred during a computation. If we were doing computations expandably, it would be trivial to set a switch to true if there was an error. In an expandable setting, this is impossible, and the only thing we can do is use the \relax side-effect of \csname...\endcsname. Namely, when such a division by zero occurs in a computation, a specific control sequence is made into \relax, and the user can query that after the end of the computation (or, more deviously, within the computation itself...).

In l3str, I want to be able to convert potentially very long strings from one encoding to another. This cannot be done by converting characters and storing them one by one in a token list (parameterless macro): since each addition takes a time proportional to the number of characters converted so far, the total time becomes quadratic in the length of the string, typically too long. Instead, the string is converted in one go. For example, say that I wish to convert a string of characters to a list of their character codes (in decimal notation), separated by commas.

\def\to@charcodes#1%
  {\expandafter\to@charcodes@\detokenize{#1}{\fi\iffalse\iffalse}\fi\fi}
\def\to@charcodes@#1%
  {\iffalse#1\fi\number`#1,\to@charcodes@}
\message{\to@charcodes{ABC}}

does the trick. Now, most of the time in conversions, the input string may not be valid. Assume for our example that we want a warning if A appears in the string. Then we simply add \if#1A\flag@on\fi to \to@charcode, with \def\flag@on{\expandafter\iffalse\csname some@flag\endcsname\fi}. To get a warning:

\ifx\some@flag\relax
  \message{Warning: backslash detected!}%
\fi

The third

is to produce pseudo-random numbers expandably without using engine-dependent primitives (see the pathetically slow l3rand in l3trial, found e.g., on the GitHub repo). The main difficulty is to have a command which expands differently each time it is called. This can be done with a combination of \csname...\endcsname and eTeX's \ifcsname. For instance, we can define a function which counts how many times it was called:

\def\howmanytimes{\howmanytimes@0;}
\def\howmanytimes@#1;%
  {%
    \ifcsname howmanytimes@#1\endcsname
      \expandafter\howmanytimes@\number\numexpr 1+%
    \else
      \expandafter\howmanytimes@end
    \fi
    #1;%
  }
\def\howmanytimes@end#1;%
  {%
    \expandafter\iffalse\csname howmanytimes@#1\endcsname\fi
    #1%
  }
\message{\howmanytimes}
\message{\howmanytimes}
\message{\howmanytimes}
\message{\howmanytimes}

prints 0 1 2 3.

share|improve this answer
    
All great ideas, but I'm not sure Knuth set things up for these tricks ;-) –  Joseph Wright Aug 11 '12 at 20:22
1  
I agree that it is mysterious why Knuth decided to do it that way. I just answered the question: "is it still useful?"... well, yes! Ah, and I forgot to mention a very odd use I made of this in combination with \aftergroup when imitating \halign as a macro. Good times :). –  Bruno Le Floch Aug 11 '12 at 21:35
    
Wow, I'm amazed. Thanks very much. I know expandable definitions have been discussed before but I always wondered if there was a limited set of such definitions which might be considered "safe". While I was aware of the \csname-\relax behaviour, I previously considered that behaviour too limited to be useful. Hence I am particularly impressed by uses two and three. –  cyberSingularity Aug 11 '12 at 21:49
    
Use one is also interesting, though seems less general due to the need for the gobble-2 effect (though I like that in your example, the \relax side effect doesn't prevent a second error showing if an unknown key is used twice, unlike the workarounds in the linked question). When you say TeXu has no equivalent, do you just mean in terms of the speed of that particular example? –  cyberSingularity Aug 11 '12 at 21:49
add comment

I'm not sure it ever had a use : if TeX had left the token undefined the classic undefined test could have been

\expandafter\ifx\csname#1\endcsname\@undefined

rather than

\expandafter\ifx\csname#1\endcsname\relax

which would have been rather clearer.

On the other hand, it is hard to find a case where it really does any harm. Joseph gave an expandable e-tex version in the linked question that ensures an error in expansion-only contexts. If you don't mind leaving a {} group (or \begingroup\endgroup group) then you can use

{\expandafter\aftergroup\csname#1\endcsname}

which just leaves the newly created token outside the group (and any definition to \relax discarded at group end.

So the only place where a \csname-that-doesnt-let-to-relax would be useful is where you are in an expansion-only context but want TeX to throw an error and not complete the expansion in the case that the token is not previously defined.

share|improve this answer
1  
I think Bruno is using something along the lines you mention in the last paragraph to set 'flags' for indicating errors in expansion contexts, for example in the LaTeX3 FPU. –  Joseph Wright Aug 10 '12 at 21:11
    
Cheers; I clearly got my cause and effect wrong in my current understanding. Thanks, it's really great to be able to discuss these things with people! But if that wasn't the use Knuth had in mind when he devised the side-effect, I wonder what was..? –  cyberSingularity Aug 10 '12 at 22:27
add comment

While only Knuth can give a definitive answer on the approach he took here, it is worth noting that the behaviour does fit in with other parts of TeX where treating things as equal to \relax is used (for example \noexpand). It also means that you can use

\csname foo\endcsname

without needing to do any form of test first. When TeX was written, there was a significant need to watch performance, and having to do

\ifcsname foo\endcsname
  \csname foo\expandafter\endcsname
\fi

would almost certainly have been an issue (more tokens, more csname building, ...). Of course, that does not apply now, but I guess you could argue that having to do a two-stage construct is still more awkward in terms of readability and dealing properly with ending conditionals.


All that tex.web seems to have on this is

@ @<Manufacture a control...@>=
begin r:=get_avail; p:=r; {head of the list of characters}
repeat get_x_token;
if cur_cs=0 then store_new_token(cur_tok);
until cur_cs<>0;
if cur_cmd<>end_cs_name then @<Complain about missing \.{\\endcsname}@>;
@<Look up the characters of list |r| in the hash table, and set |cur_cs|@>;
flush_list(r);
if eq_type(cur_cs)=undefined_cs then
  begin eq_define(cur_cs,relax,256); {N.B.: The |save_stack| might change}
  end; {the control sequence will now match `\.{\\relax}'}
cur_tok:=cur_cs+cs_token_flag; back_input;
end

which does not give much away other than the outcome.

share|improve this answer
    
Thanks, that's very insightful. I don't know how common it was (before LaTeX) to use the \csname construct for invoking commands rather than defining commands (which is all I believe The TeXbook and plain.tex use it for, though I confess I don't understand \newhelp), and there would be no need for any tests in such circumstances. However, your observation about consistency is certainly logical. I was also musing (perhaps not seriously) about how easily one can add new primitives, and the tex.web code is helpful there (though compiling TeX from web source is beyond me currently)! –  cyberSingularity Aug 11 '12 at 8:40
    
You should as well mention that in the double-\csname construct, if foo was something complicated, if would have to be either \edefed or expanded twice. Both solutions would be too complicated. –  tohecz Aug 12 '12 at 20:31
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.