4

This is a general and documented feature of latex3, but I shall still provide an MWE in order to illustrate the problem, see below.

Suppose I have a function which uses the l3keys key-value interface, and I want it to have reasonable defaults for when the user does not provide the key. l3keys provides the default and initial options, where default is used when the key is given without a value and initial is used to initialise the key. However, this initialisation happens exactly once, at the time the key is defined.

\documentclass{standalone}
\begin{document}
\ExplSyntaxOn
\keys_define:nn { mykeys } {
  myvalue .int_set:N = \l_myvalue_int,
  myvalue .initial:n = 0
}
\cs_new:Nn \show_zero_or_myvalue:n {
  \keys_set:nn { mykeys } { #1 }
  \int_use:N \l_myvalue_int
}

show_zero_or_myvalue:n {}
show_zero_or_myvalue:n { myvalue=5 }
show_zero_or_myvalue:n {}
\ExplSyntaxOff
\end{document}

As a user, with the function definition hidden in some package, I would expect this to result in the output 050. Of course, once you read the l3keys documentation, you know that it actually prints 055, because the key myvalue is not set in the third call, so it retains its previous value.

However, there are situations where this is undesirable. Imagine you were drawing a picture with TikZ and the code

\tikz[color=black]{
% define some nodes
\draw[color=red] (a) -- (b);
\draw (b) -- (c);
}

resulted in two red lines.

Obviously, I can reset the key in the backend by hand, but since I am working with a large collection of keys that are read in multiple places, my current workaround is that before every call to \keys_set:nn { mykeys } { #1 }, I issue a manual \keys_set:nn { mykeys } { ... }, where ... is a long, long list of keys.

Is there a better way to do this, either built into l3keys or by hooking into the set_keys mechanism?

There have been questions on this topic a while ago, but none with a definitive answer. Since latex3 is still being developed, I think asking again is reasonable.

Related: if there is no built-in way, what is the standard mechanism to propose the inclusion of this feature? Evidently I am not the only person who would like to see something like this.

2
  • 2
    It sounds like you want to group the settings: that's nothing to do with keys per se though
    – Joseph Wright
    Commented Nov 8, 2022 at 10:31
  • TikZ/PGFkeys works the same: \path begins and ; ends a group. Commented Nov 8, 2022 at 21:32

2 Answers 2

5

There are two strategies for this.

One is what's employed also by TikZ, namely grouping.

\documentclass{article}
\begin{document}
\ExplSyntaxOn
\keys_define:nn { mykeys } {
  myvalue .int_set:N = \l_myvalue_int,
  myvalue .initial:n = 0
}
\cs_new_protected:Nn \show_zero_or_myvalue:n {
  \group_begin:
  \keys_set:nn { mykeys } { #1 }
  \int_use:N \l_myvalue_int
  \group_end:
}

\show_zero_or_myvalue:n {}
\show_zero_or_myvalue:n { myvalue=5 }
\show_zero_or_myvalue:n {}
\ExplSyntaxOff
\end{document}

Since the setting of the keys is done locally, the initial value will be restored upon group ending.

Second strategy: keep a list of the keys that should be reset.

\documentclass{article}
\begin{document}
\ExplSyntaxOn
\keys_define:nn { mykeys } {
  myvalue .int_set:N = \l_myvalue_int,
}
\cs_new_protected:Nn \show_zero_or_myvalue:n {
  \keys_set:nn { mykeys } { myvalue=0,#1 }
  \int_use:N \l_myvalue_int
}

\show_zero_or_myvalue:n {}
\show_zero_or_myvalue:n { myvalue=5 }
\show_zero_or_myvalue:n {}
\ExplSyntaxOff
\end{document}

If you have several keys to reset, you can define a shorthand

\cs_new_protected:Nn \betta_reset: {
  \keys_set:nn { mykeys } { myvalue=0 }
}

and add \betta_reset: before \keys_set:nn in the function \show_zero_or_myvalue:n.

1
  • Fair enough, I forgot about grouping. I was explicitly looking for a way to avoid adding a \betta_reset style function, so grouping does what I want. Commented Nov 8, 2022 at 12:46
7

Another alternative in expl3 to the possibilities shown by @egreg is to precompile standard-settings into a token list. This is (in principal) the same idea as

Second strategy: keep a list of the keys that should be reset.

but is faster.

\documentclass{standalone}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_bettageorge_defaults_tl
\keys_define:nn { mykeys } {
  myvalue .int_set:N = \l_myvalue_int,
  myvalue .initial:n = 0
}
\keys_precompile:nnN { mykeys } { myvalue=0 } \l_bettageorge_defaults_tl
\cs_new_protected:Nn \show_zero_or_myvalue:n {
  \l_bettageorge_defaults_tl
  \keys_set:nn { mykeys } { #1 }
  \int_use:N \l_myvalue_int
}

\show_zero_or_myvalue:n {}
\show_zero_or_myvalue:n { myvalue=5 }
\show_zero_or_myvalue:n {}
\ExplSyntaxOff
\end{document}

You must log in to answer this question.

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