I have a (potentially) long property list, which values, at the moment, are just token lists. Now, I want to implement that some of the keys may have multiple values. I will store these multiple values in clists.

So, for each key I have to test if the value is a clist or just a token list. The case where the key may have just only one value can be seen as a special case of the clist, where just only one value can be inserted in the list.

I ask for advice, which approach will be easier to program:

  1. values that can be either token lists or clists? or
  2. values that all are clists, but some of them can only have one element?

(key, value) pairs will be set usually just once, and the value will be retrieved a few times (some of them several times, but I don't spect more than five times). I don't foresee a big difference in running time for both approaches. I an not sure if memory efficiency will be an issue with the "all clist approach."


egreg's answwr is great (as usual). But I did not explain the problem at full. At the time to set the (key, value) pair for the first time, I don't have all the elements of list (if it is a list). So, I would have to:

  1. Retrieve the value,
  2. Check if it a list,
  3. Insert the new value in the list

several times until the list type keys are filled. If I define all the values as clists. I can skip step number 2. But them, when retrieved I guess I have to check if the key is a list or not.

The question boils down to the point if skipping step 2 make programming easier or not.

(After a deeper thought, it probably is equally easy/complicated because it is just moving the harder part to the setting or the retrieving of the values)

  • I solved a similar problem for myself using a second property list, storing datatypes of entries (though in my case there are also integers, dimensions, etc. possible).
    – Skillmon
    Oct 29, 2018 at 8:10
  • @Skillmon I will create for sure a second prop with will contain for each key that is should contain a list true. But my question is if it is easier to program the retrieve of values if all are lists.
    – TeXtnik
    Oct 29, 2018 at 8:16
  • Depends on what you want to do with the retrieved values and what should be in the token lists. The retrieval of values shouldn't be that hard either way. \NewDocumentCommand\PrintKey{m}{ \prop_get:NnN \l_TeXtnik_key_types_prop { #1 } \l_TeXtnik_tmp_tl \exp_args:NV \tl_if_eq:nnTF \l_TeXtnik_tmp_tl { clist } { \TeXtnik_get_clist:n { #1 } } { \TeXtnik_get_tl:n { #1 } } } and you're done. You could as well write above expandable (but slower) with \prop_item:Nn.
    – Skillmon
    Oct 29, 2018 at 8:23

1 Answer 1


\prop_put:Nnn is agnostic about the data you store in the sense that it does no interpretation to it; it's much like \tl_set:Nn in this respect, so in a sense a property list (plist) is a collection of token lists (tl) indexed by name.

Can this be a collection of clists? Yes, why not?

You can store the value as usual

\prop_put:Nnn \l_textnik_test_prop { a } { 1,2,3,4 }

and then retrieve it by assigning it to a tl variable:

\cs_new_protected:Nn \textnik_prop_get_clist:NnN
  \prop_get:NnN #1 {#2} \l__textnik_prop_get_clist_tl
  \clist_set:NV #3 \l__textnik_prop_get_clist_tl

so that

\textnik_prop_get_clist:NnN \l_textnik_test_prop { a } \l_textnik_test_clist

will do the same as

\clist_set:Nn \l_textnik_test_clist { 1,2,3,4 }

If you want to extract the value as a tl, use \clist_get:NnN.

Here's a different implementation: each property refers to a clist.


% Define a new data type pcl, only local settings.
% Add variants as needed and support for global setting.
\cs_new_eq:NN \textnik_pcl_new:N \prop_new:N
\cs_new_eq:NN \textnik_pcl_clear_new:N \prop_clear_new:N
\cs_new_eq:NN \textnik_pcl_clear:N \prop_clear:N
\cs_new_eq:NN \textnik_pcl_set_eq:NN \prop_set_eq:NN
\cs_new_eq:NN \textnik_pcl_remove:NN \prop_remove:NN

% a global counter
\int_new:N \g__textnik_pcl_serial_int

\cs_new_protected:Nn \__textnik_pcl_check:Nn
  \prop_if_in:NnF #1 { #2 }
   {% the property doesn't already exist
    \int_gincr:N \g__textnik_pcl_serial_int
    \prop_put:Nnx #1 { #2 } { \int_to_arabic:n { \g__textnik_pcl_serial_int } }
    \clist_new:c { l__textnik_pcl_ \int_to_arabic:n { \g__textnik_pcl_serial_int } _clist }

% adding items to a pcl
\cs_new_protected:Nn \textnik_pcl_put:Nnn
  \__textnik_pcl_check:Nn #1 { #2 }
  \clist_set:cn { l__textnik_pcl_ \prop_item:Nn #1 { #2 } _clist } { #3 }
\cs_new_protected:Nn \textnik_pcl_put_left:Nnn
  \__textnik_pcl_check:Nn #1 { #2 }
  \clist_put_left:cn { l__textnik_pcl_ \prop_item:Nn #1 { #2 } _clist } { #3 }
\cs_new_protected:Nn \textnik_pcl_put_right:Nnn
  \__textnik_pcl_check:Nn #1 { #2 }
  \clist_put_right:cn { l__textnik_pcl_ \prop_item:Nn #1 { #2 } _clist } { #3 }

% retrieving items from a pcl
\cs_new_protected:Nn \textnik_pcl_get:NnN
  \clist_set_eq:Nc #3 { l__textnik_pcl_ \prop_item:Nn #1 { #2 } _clist }

% showing a pcl
\cs_new_protected:Nn \textnik_pcl_show:N
  \prop_map_function:NN #1 \__textnik_pcl_show:nn
\cs_new_protected:Nn \__textnik_pcl_show:nn
  \clist_show:c { l__textnik_pcl_ #2 _clist }

%%%% Test

\textnik_pcl_new:N \l_textnik_test_pcl
\textnik_pcl_put:Nnn \l_textnik_test_pcl { A } { A1,A2,A3 }
\textnik_pcl_put_right:Nnn \l_textnik_test_pcl { A } { A4,A5 }
\textnik_pcl_put_left:Nnn \l_textnik_test_pcl { A } { A0 }
\textnik_pcl_put:Nnn \l_textnik_test_pcl { B } { B1,B2,B3 }
\textnik_pcl_put_right:Nnn \l_textnik_test_pcl { B } { B4,B5 }
\textnik_pcl_put_left:Nnn \l_textnik_test_pcl { B } { B0 }

\clist_new:N \l_textnik_test_clist
\textnik_pcl_get:NnN \l_textnik_test_pcl {A} \l_textnik_test_clist
\clist_show:N \l_textnik_test_clist
\textnik_pcl_get:NnN \l_textnik_test_pcl {B} \l_textnik_test_clist
\clist_show:N \l_textnik_test_clist

%\textnik_pcl_show:N \l_textnik_test_pcl

A pcl is actually a prop, but the properties stored are just numbers that refer to an array of clists.

The output is

The comma list \l_textnik_test_clist contains the items (without outer
>  {A0}
>  {A1}
>  {A2}
>  {A3}
>  {A4}
>  {A5}.
<recently read> }
l.71 \clist_show:N \l_textnik_test_clist
The comma list \l_textnik_test_clist contains the items (without outer
>  {B0}
>  {B1}
>  {B2}
>  {B3}
>  {B4}
>  {B5}.
<recently read> }
l.73 \clist_show:N \l_textnik_test_clist
  • Thanks for the answer. I have edited to clarify further my question.
    – TeXtnik
    Oct 30, 2018 at 10:28
  • @TeXtnik I added a different approach
    – egreg
    Oct 30, 2018 at 11:04
  • Thank you very much. I need to study this carefully, :-) but I probably will use this apprach.
    – TeXtnik
    Oct 30, 2018 at 13:55
  • @TeXtnik Since adding an item to a pcl increases a global counter, the limit is 2³¹ such additions. I don't think it should bother you. ;-)
    – egreg
    Oct 30, 2018 at 13:59
  • No, It is no a problem!
    – TeXtnik
    Oct 30, 2018 at 14:33

You must log in to answer this question.

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