3

Edit (context)

For a class myclass I'm working on, I want the user be able to specify (the characteristics of) the institute, subinstitute, subsubinstitute, etc. he is affiliated to. Because the number of (sub(sub(...)))institutes is unpredictable, I want the user to be able to specify these characteristics through a single command, say \setinstitute with ⟨key⟩ = ⟨value⟩ syntax:

\setinstitute{
  name      = ⟨name⟩,
  url       = ⟨url⟩,
  logo file = ⟨logo file⟩,
}

that may be used as many times as necessary.

For the ⟨key⟩ = ⟨value⟩ syntax, I'm using the l3keys module and its nice .prop_put:N syntax:

\keys_define:nn { myclass/institute }
{
  name        .prop_put:N = \l_tmpa_prop,
  url         .prop_put:N = \l_tmpa_prop,
  logo~ file  .prop_put:N = \l_tmpa_prop,
}

Hence, the characteristics of the institutes are stored in property list(s).

Now, the order of the institutes specified should tell the "depth" of each of them and I have to be able to retrieve e.g. the name of the 3rd institute. Hence a sequence, say \g__myclass_institutes_seq:

\NewDocumentCommand \setinstitute { m } {
  \keys_set:nn { myclass/institute } { #1 }
  \seq_gput_left:Nn \g__myclass_institutes_seq { \l_tmpa_prop }
}

The point is, it is always the same temporary property list which is used and the sequence contains only multiple replications of the last entered characteristics. Hence, property lists with variable names which are made equal to the temporary one before being added to the sequence:

\int_new:N \g__myclass_institutes_number_int

\NewDocumentCommand \setinstitute { m } {
  \keys_set:nn { myclass/institute } { #1 }
  \int_gincr:N \g__myclass_institutes_number_int
  \__myclass_populate_institutes_seq:n {
    \int_use:N \g__myclass_institutes_number_int
  }
}

\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
{
  \prop_new:c {l__myclass_institute_#1_prop}
  \prop_set_eq:cN {l__myclass_institute_#1_prop} \l_tmpa_prop
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % The 3 following lines of code were wrong         %
  % and are replaced by the ones suggested by @egreg %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \seq_gput_left:Nn \g__myclass_institutes_seq {
  %   \l__myclass_institute_#1_prop
  % }
  \seq_gput_left:Nx \g__myclass_institutes_seq {
    \exp_not:c {l__myclass_institute_#1_prop}
  }
}

Here is a complete example:

\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
  {myclass}
  {2020/07/10}
  {0.1}
  {
    My~Nice~Class.%
  }
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }
%
\ExplSyntaxOn

\prop_new:N \l__myclass_institute_prop
\seq_new:N \g__myclass_institutes_seq
\int_new:N \g__myclass_institutes_number_int

\keys_define:nn { myclass/institute }
{
  name         .prop_put:N = \l_tmpa_prop,
  url          .prop_put:N = \l_tmpa_prop,
  logo~ file   .prop_put:N = \l_tmpa_prop,
}

\NewDocumentCommand \setinstitute { m } {
  \keys_set:nn { myclass/institute } { #1 }
  \int_gincr:N \g__myclass_institutes_number_int
  \__myclass_populate_institutes_seq:n {
    \int_use:N \g__myclass_institutes_number_int
  }
}

\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
{
  \prop_new:c {l__myclass_institute_#1_prop}
  \prop_set_eq:cN {l__myclass_institute_#1_prop} \l_tmpa_prop
  \prop_clear:N \l_tmpa_prop
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % The 3 following lines of code were wrong         %
  % and are replaced by the ones suggested by @egreg %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \seq_gput_left:Nn \g__myclass_institutes_seq {
  %   \l__myclass_institute_#1_prop
  % }
  \seq_gput_left:Nx \g__myclass_institutes_seq {
    \exp_not:c {l__myclass_institute_#1_prop}
  }
}

\NewDocumentCommand \displayinstitutes {  } {
  \seq_reverse:N \g__myclass_institutes_seq
  \seq_map_indexed_inline:Nn \g__myclass_institutes_seq {
    \begin{description}
    \item[Institute~##1:]\
      % \prop_show:N ##2
      \begin{description}
        \prop_map_inline:Nn ##2 {
        \item[####1:]####2
        }
      \end{description}
    \end{description}
  }
}

\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}

\documentclass{myclass}
\begin{document}
\setinstitute{
  name      = foo1,
  url       = bar1,
  logo file = baz1,
}
\setinstitute{
  name      = foo2,
  url       = bar2,
  logo file = baz2,
}
\displayinstitutes
\end{document}

But it is far from impossible that I misused expl3 here.

Original post

I'm trying to create an expl3 sequence of property lists, the names of the latter being parameterized (containing an integer parameter): \l_#1_prop. It is easy to add entries to such property lists thanks to the c specifier:

\prop_put:cnn {l_#1_prop} {key} {value}

Because \seq_put_left:Nc doesn't exist (and isn't accepted as a variant), I tried to add to the sequences the property lists with \l_#1_prop:

  \seq_put_left:Nn \l_tmpa_seq {
    \l_#1_prop
  }

but this results in sequence items as \l_ #1_prop (note the spurious space) instead of \l_#1_prop.

This is exemplified by the following MCE:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand \test { m m } {
  \prop_new:c {l_#1_prop}
  \prop_put:cnn {l_#1_prop} {key} {#2}
  \seq_put_left:Nn \l_tmpa_seq {
    \l_#1_prop
  }
  \prop_show:c {l_#1_prop}
  \seq_show:N \l_tmpa_seq
}
\ExplSyntaxOff

\begin{document}
\test{1}{a}
\end{document}

the shown property list and sequence giving respectively \l_1_prop and \l_ 1_prop:

The property list \l_1_prop contains the pairs (without outer braces):
>  {key}  =>  {a}.
<recently read> }
                 
l.17 \test{1}{a}
                
? 
The sequence \l_tmpa_seq contains the items (without outer braces):
>  {\l_ 1_prop}.
<recently read> }
                 
l.17 \test{1}{a}
                
?

Do you know where the spurious space is coming from and how to get rid of it?

3
  • 1
    You want to put a property list inside a sequence? There is no spurious space, the item in the sequence consists of the seven tokens \l_•1•_•p•r•o•p (the bullet just separates tokens).
    – egreg
    Jul 10, 2020 at 17:37
  • 1
    \seq_put_left:Nx \l_tmpa_seq { \exp_not:c { l_#1_prop } } Of course you should use a better name for your variables. And I see no real reason to put the property list in the sequence, when #1 suffices.
    – egreg
    Jul 10, 2020 at 17:42
  • 1
    tex always shows a space after command sequences with letters in their name, the space after \_ is the same as the space after \zz in \def\foo{\zz1}\show\foo > \foo=macro: ->\zz 1. Jul 10, 2020 at 18:18

1 Answer 1

5

I see no reason to put the entire property list in the sequence: just put the index and when you need to retrieve something from the property list you can use the index, say with

\prop_item:cn { l_ \seq_item:Nn \l_tmpa_tl {1} _ prop} } { foo }

in order to obtain the property foo from the property list with the index stored in the first position of the sequence.

Anyway, if you want to store the full name, you can do

\seq_put_left:Nx \l_tmpa_tl { \exp_not:c { l_#1_prop } }

What you see is not a spurious space. You're storing as the sequence item several tokens

\l_•1•_•p•r•o•p

(bullets just separate tokens for clarity) and TeX always adds a space after a control word when asked to \show some token list.


Update

Here's an edited version of your code where I show how you can just store the index.

\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
  {myclass}
  {2020/07/10}
  {0.1}
  {
    My~Nice~Class.
  }
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }

\ExplSyntaxOn

\prop_new:N \l__myclass_institute_prop
\prop_new:N \l__myclass_tmpa_prop
\seq_new:N \g__myclass_institutes_seq
\int_new:N \g__myclass_institutes_number_int

\keys_define:nn { myclass/institute }
 {
  name         .prop_put:N = \l__myclass_tmpa_prop,
  url          .prop_put:N = \l__myclass_tmpa_prop,
  logo~ file   .prop_put:N = \l__myclass_tmpa_prop,
 }

\NewDocumentCommand \setinstitute { m }
 {
  \prop_clear:N \l__myclass_tmpa_prop
  \keys_set:nn { myclass/institute } { #1 }
  \int_gincr:N \g__myclass_institutes_number_int
  \__myclass_populate_institutes_seq:V \g__myclass_institutes_number_int
 }

\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
 {
  \prop_new:c {l__myclass_institute_#1_prop}
  \prop_set_eq:cN {l__myclass_institute_#1_prop} \l__myclass_tmpa_prop
  \seq_gput_left:Nn \g__myclass_institutes_seq { #1 }
 }
\cs_generate_variant:Nn \__myclass_populate_institutes_seq:n { V }

\NewDocumentCommand \displayinstitutes {  }
 {
  \seq_set_eq:NN \l_tmpa_seq \g__myclass_institutes_seq
  \seq_reverse:N \l_tmpa_seq
  \seq_map_indexed_inline:Nn \l_tmpa_seq
   {
    \begin{description}
    \item[Institute~##1:]\mbox{}
    %\prop_show:c { l__myclass_institute_##2_prop }
      \begin{description}
        \prop_map_inline:cn { l__myclass_institute_##2_prop }
         {
          \item[####1:]####2
         }
      \end{description}
    \end{description}
   }
 }

\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}

\documentclass{myclass}
\begin{document}
\setinstitute{
  name      = foo1,
  url       = bar1,
  logo file = baz1,
}
\setinstitute{
  name      = foo2,
  url       = bar2,
  logo file = baz2,
}
\displayinstitutes
\end{document}

However, since the index is just a number which is incremented at each call of \setinstitute, you don't even need the sequence: just call the property list by the index.

\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
  {myclass}
  {2020/07/10}
  {0.1}
  {
    My~Nice~Class.
  }
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }

\ExplSyntaxOn

\prop_new:N \l__myclass_institute_prop
\prop_new:N \l__myclass_tmpa_prop
\int_new:N \g__myclass_institutes_number_int

\keys_define:nn { myclass/institute }
 {
  name         .prop_put:N = \l__myclass_tmpa_prop,
  url          .prop_put:N = \l__myclass_tmpa_prop,
  logo~ file   .prop_put:N = \l__myclass_tmpa_prop,
 }

\NewDocumentCommand \setinstitute { m }
 {
  \prop_clear:N \l__myclass_tmpa_prop
  \keys_set:nn { myclass/institute } { #1 }
  \int_gincr:N \g__myclass_institutes_number_int
  \prop_new:c {l__myclass_institute_ \int_use:N \g__myclass_institutes_number_int _prop}
  \prop_set_eq:cN
   {l__myclass_institute_ \int_use:N \g__myclass_institutes_number_int _prop}
   \l__myclass_tmpa_prop
 }

\NewDocumentCommand \displayinstitutes {  }
 {
  \int_step_inline:nn { \g__myclass_institutes_number_int }
   {
    \begin{description}
    \item[Institute~##1:]\mbox{}
    %\prop_show:c { l__myclass_institute_##1_prop }
      \begin{description}
        \prop_map_inline:cn { l__myclass_institute_##1_prop }
         {
          \item[####1:]####2
         }
      \end{description}
    \end{description}
   }
 }

\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}

\documentclass{myclass}
\begin{document}
\setinstitute{
  name      = foo1,
  url       = bar1,
  logo file = baz1,
}
\setinstitute{
  name      = foo2,
  url       = bar2,
  logo file = baz2,
}
\displayinstitutes
\end{document}
5
  • It is far from impossible that I misused expl3 here. I'll edit my question in order to explain the context. Jul 10, 2020 at 19:42
  • I'm not sure to understand what you mean by "just put the index" and if it is suitable in my context (detailed in my edited question). Anyway, \seq_put_left:Nx \l_tmpa_tl { \exp_not:c { l_#1_prop } } (except \l_tmpa_tl which should be \l_tmpa_seq I guess) works like a charm! Jul 10, 2020 at 21:02
  • 2
    @DenisBitouzé I added my versions of your code.
    – egreg
    Jul 10, 2020 at 21:39
  • I wasn't aware of \int_step_inline:nn: thanks for sharing! Do you really know by heart every one of the thousands of expl3 commands?! :) Jul 11, 2020 at 8:59
  • 1
    @DenisBitouzé No, but I've used them a lot.
    – egreg
    Jul 11, 2020 at 9:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .