Loop steps from 1 through 9. Each step puts current index digit of the loop into a box and extracts the digit's width. The width is then appended as dimension value to a sequence. Although the sequence contains 9 values at the end, oddly all of them are dimension (width) of digit 9. All values of the sequence are overwritten to new dimension at each step. Maybe you can figure out the core of the problem.


  { \hbox_set:Nn\myBox{#1}
    % display dimension before adding it to sequence
    #1=\dim_eval:n{\box_wd:N\myBox}\\ % output
    % add dimension to sequence
    % display current contents of the sequence
% display all dimensions (contains only duplicates of last dimension)



You need to expand the value: use



What's the problem? If you do

\hbox_set:Nn \l_tmpa_box { A }
\seq_put_right:Nn \l_tmpa_seq { \dim_eval:n { \box_wd:N \l_tmpa_box } }
\hbox_set:Nn \l_tmpa_box { AA }
\seq_put_right:Nn \l_tmpa_seq { \dim_eval:n { \box_wd:N \l_tmpa_box } }

this results in the sequence to contain the following items (without the outer braces, as it would be displayed by \seq_show:N \l_tmpa_seq)

{ \dim_eval:n { \box_wd:N \l_tmpa_box } }
{ \dim_eval:n { \box_wd:N \l_tmpa_box } }

When the sequence is used, the width of the current contents of \l_tmpa_box is employed: the value it had at the moment of assignment has never been mentioned.

With \seq_put_right:Nx you instead get the value frozen at the moment of the assignment.

Would it be “better” to use

\exp_args:NNx \seq_put_right:Nn \l_tmpa_tl {...}

No. Using (or defining, in case of need) a variant is better style.

  • 1
    @bp2017 In my opinion it’s better to use variants, as in the present case – egreg May 26 at 15:19
  • @PhelypeOleinik Yes, of course – egreg May 27 at 11:04

When you do:

\seq_put_right:Nn \mySeq { \dim_eval:n{ \box_wd:N \myBox } }

what you are appending to your sequence is the token list \dim_eval:n{\box_wd:N\myBox} (the tokens are \dim_eval:n, { with catcode 1, \box_wd:N, \myBox and } with catcode 2). The final \dim_eval:n is evaluated too late, once the loop has been fully executed and you do \seq_use:Nn \mySeq {,~}. At this point, \myBox contains the digit 9, hence what you saw. As egreg said (faster than me), replace \seq_put_right:Nn with \seq_put_right:Nx to evaluate \dim_eval:n inside the loop, when \myBox still contains the relevant digit.

You have to realize that your sequence variable \mySeq does not contain any length at all: it contains n times the same token list, which I explicitated above, with n=0 at first, then n=1, ..., and finally n=9. In other words, it contains n times the same “formula,” stored in the form of a token list. This formula is comparable to a function of one variable, the box variable \myBox. Whenever you use \seq_use:Nn \mySeq {...}, you put n copies of the same formula in the input stream (where n is the current length of \mySeq), and when TeX expands one of the \dim_eval:n tokens and processes all tokens resulting from this expansion, this yields a length (precisely: a 〈dimen〉) according to the formula and the contents of \myBox at that point.

At the end of your example, your code therefore computes n=9 times the same formula with the same value of \myBox, an \hbox containing the figure 9. In very explicit terms, your final \seq_use:Nn call is equivalent to this:

\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox } ,~
\dim_eval:n { \box_wd:N \myBox }

Calculating 9 times f(x) with the same function f and the same value of x gives 9 times the same result, hence the output you obtained.

For the \seq_use:Nn calls inside the loop, this is exactly the same, except that n is replaced by a number between 1 and 8, inclusive.

Note: as people already told you, your variables don't respect the LaTeX3 coding guidelines. Read expl3.pdf and l3styleguide.pdf from here (the beginning of interface3.pdf is also pretty useful to read at first, but I suppose you've already seen it).

  • I got tired to tell the OP about following the guidelines – egreg May 26 at 8:00
  • @egreg Let's hope that with time comes wisdom. :-) – frougon May 26 at 8:02
  • @egreg, and frougon, why is it necessary to introduce additional complexity into your code (especially in a testing environment, here) and peer into it every time trying to distinguish your variables and functions from expl3-defined ones? On the contrary, regular naming (everyone had been using before expl3) looks easily distinguishable from expl3 naming, so the "guidelines" are more appropriate for the expl3 team/authors than for those who use the package (because the contrast in naming conventions makes the code easy to read; imposing same naming conventions on users is a mistake). – bp2017 May 26 at 14:33
  • You say \dim_eval:n is evaluated too late. But how late is too late? Is it evaluated at the end of the loop? If so, why do I get results at each iteration? – bp2017 May 26 at 15:01
  • 2
    1) For code in a file that is never going to be a package, using \l_my_ and \g_my_ prefixes is probably acceptable, but the day you want to reuse such code with another one developed in the same way, you're trapped and have to rename everything. 2) The distinction between local and global assignments on the one hand, and local and global variables on the other hand, is very important. The naming convention helps a lot avoid errors. 3) If you want to understand well expansion, read the TeXbook (study each exercise!). LaTeX3 will become much clearer after that. – frougon May 26 at 18:35

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.