As far as I am aware, there is no mechanism in l3keys to preset keys like the xkeyval supports.

I explicitly do not mean the .default:n specification in l3keys, since this is invoced if the key is given but no =value is present.

With the following definition

\keys_define:nn { module }
  keya      .tl_set:N  = \l_keya_tl,
  keya      .default:n = { foo },
  keyb      .tl_set:N  = \l_keyb_tl,
  keyb      .default:n = { bar },

the invocation \keys_set:nn { module } { keya } will set \l_keya_tl to foo, as this is the default value. But I would like \keys_set:nn { module } { } to also change the value of the \l_keya_tl variable, e.g. to \c_novalue_tl so that after setting the keys, I can differentiate between

  • the user has not given the key at all (no value supplied)
  • the user set the key (with or without an =, this is handled by the .default:n)

Currently, I just run \tl_set_eq:NN \l_key_tl \c_novalue_tl before setting the keys, then I can test if the user gave the key with

\tl_if_novalue:VTF \l_my_tl { no value specified } { handle user value }

and of course this works just fine.

Is it a design choice to not provide such features in l3keys (e.g. because they are considered poor style), or is this just not implemented as it is not needed often?

Also note that this beahviour is very similar to using .initial:n and then use grouping to set keys locally whenever setting them, so that the initial:n never changes. This is, however, not an option for me in some situations.

Currently my approach is to just manually execute an additional \keys_set:nn { module } { keys, to, preset }, and then setting the user keys, but this seems tedious.

From what gusbrs pointed out, I get that with How to distinguish "no value" from "empty value" when setting `l3keys`? can distinguish the situations

  • \keys_set:nn { module } { keya, keyb = bar }, where the key has been set and no value is provided at all. This will be handled by .default:n, which is - if present, equivalent to having called keya = <default>
  • \keys_set:nn { module } { keya=, keyb = bar }, where the key has been explicitly set, but to the empty token list.
  • keys_set:nn { module } { keya = foo, keyb = bar}, where we regularly set a value

What I want is to also detect the

  • \keys_set:nn { module } { keyb = bar } situation, in which case I would e.g. also want to execute the .default:n handler (for types that don't support the absence of a value), but in the case of a token list also be able to execute \tl_set_eq:NN \l_keya_tl \c_novalue_tl in this case.

I could imagine this to be handled by some kind of .preset:n property that gets executed *every time keys are set for this module` before processing the keys, no matter what keys are given.

This would

  • guarantee that there is actually a value after setting the keys
  • also handle the token list case by specifying .preset:V = \c_novalue_tl, which would yield my desired behaviour.

Have a look at the section on 'Presetting keys' in the xkeyval documentation, this is what I intend to have.

  • The entire l3keys concept is that there is no such thing as a key having no value: they exist once you create them and may have an empty value.
    – Joseph Wright
    Commented Jan 31, 2022 at 13:57
  • To be clear why I see it that way: keys which are not token lists can't contain no value at all - if you for example have one as an int, you need to be able to use the value whether it's set or not.
    – Joseph Wright
    Commented Jan 31, 2022 at 13:59
  • But isn't it a reasonably use case to have some key-value syntax macro, say \foo[key1 = val1, key2 = val2]{something}, and if key2has not been given, we use some kind of fallback, so the key behaves like an optional argument? Commented Jan 31, 2022 at 14:00
  • Yes, but even in the case of an int, we might want to reset the int to say 0 in case the key is not specified. This way we make sure that the int has a value, but we don't just end up using the int value from the previous invocation, which could be anything. Commented Jan 31, 2022 at 14:01
  • The good advice you received notwithstanding: tex.stackexchange.com/q/614690/105447
    – gusbrs
    Commented Jan 31, 2022 at 14:01


You must log in to answer this question.

Browse other questions tagged .