4

When playing with recursive functions of expl3 it has happened several times to me that a quark got expanded unintentionally, in which case TeX will go into an infinite expansion loop. (What is extra annoying is that my console doesn't react to Ctrl+C in that case, so that I have to kill the process manually.)

So I'm wondering if quarks have to be defined in that self-expanding manner at all. There seem to be two use cases for them:

  1. As delimiters of various functions with delimited parameters, e.g. \q_recursion_stop. In that case the definition of the quark doesn't even matter, because TeX's expansion mechanism only scans for a token with that name, no matter if it is defined or not.

  2. When comparing if a token is equal to a quark, e.g. \quark_if_recursion_tail_stop:N has a test

    \if_meaning:w \q_recursion_tail #1 ... \fi:
    

    \if_meaning:w is the same as \ifx, so it doesn't really expand the macros here but does an internal comparison of each token in the replacement text. That means we don't need a recursive macro in this case either. A definition like

    \cs_new:Nn \quark {\quark_undefined}
    

    would be fine as well, while at the same time preventing accidental infinite loops.

Are there situations in which it's absolutely necessary to have a recursive quark definition?

  • With your definition ( which was used even back in 2.09 days) you need a new undefined csname each time or they are all ifx equal – David Carlisle May 31 at 5:54
  • Yes, \quark was meant to be a general pattern for a quark name, so that the definition also includes a new command each time. As the number of quarks in a program should be very low, this wouldn't be a problem. – siracusa May 31 at 17:44
6

My first thought for an answer was "yes, otherwise they wouldn't be quarks" as that is the definition, so it's like asking if triangles have to have three sides. But the implied question is "Are quarks useful things to use in macro definitions?".

LaTeX 2e, and 2.09 (and possibly earlier) have a definition similar to the one you suggest. \@nil is undefined and often used at the end of a list of tokens and \@nnil is defined by

\def\@nnil{\@nil}

Quarks were designed as an abstraction of this, while addressing some issues with this setup.

  • It can be somewhat confusing when reading code whether \@nil or \@nnil should be used, if you use a delimited argumment, or iterate through the list using \futurelet you need to use \@nil but if you iterate through the list using \def\tmp{#1}\ifx\tmp\@nnil... you need to use \@nnil as the final step would have \def\tmp{\@nil} which is not \ifx equal to \@nil. Quarks get rid of this distinction, allowing the same name to be used in all these contexts.

  • To make a new distinct delimiter you need another two csnames, (your suggested definition would make all quarks ifx equal, you would want a unique undefined token in each case). In that era latex was critically short of csnames, the main reason that initially so many commands were fragile is that defining a protect version of \fragilefoo as \def\foo{\protect\fragilefoo} would double the csname usage and then latex simply would not fit in the tex implementations of the time.

The downside of these benefits is of course the somewhat brutal error behaviour with a tight infinite loop. To help warn against that the name "quark" was used, to warn that they needed to be handled with care and probably shouldn't be used on their own.....

5

The definition means that

\tl_set:Nn \l_tmpa_tl { \q_no_value }
\quark_if_no_value:NTF \l_tmpa_tl

will be logically true. This makes it possible to have fast tests for the presence of quarks when dealing with a single token. Although perhaps less important today, there is a speed gain in this approach over other possibilities. Quarks were set up for handling cases in tight loops, where speed gains of this type can become significant.

The reason is of course we are doing

\cs_set_nopar:Npn \q_no_value { \q_no_value }
\cs_set_nopar:Npn \l_tmpa_tl { \q_no_value }
\if_meaning:w \q_no_value \l_tmpa_tl % \tex_ifx:D

which is true: both are ultimately (non-\long) macros expanding to \q_no_value.

Some parts of expl3 go back a long way, and here there is of course some 'history'. With \pdfstrcmp available, one can do many tests on a string basis: this was not possible when expl3 was first being developed, and perhaps one might take a different tack here if starting today.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.