162

TUGboat, Volume 43 (2022), No. 2

Key–value setting handling in theLATEX kernel
Joseph Wright, LATEX Project Team
1Introduction\RequirePackage{kvoptions}\DeclareStringOption[me]{name}\DeclareBoolOption{draft}\DeclareComplementaryOption{final}{draft}\DeclareDefaultOption{\ERROR}\ProcessKeyvalOptions*E ε introduced the idea of classes and packages,
and along with that the concept of class and package options. These are nowadays very familiar toLATEX authors, with the first optional argument to\documentclass and \usepackage used in the vast
majority of LATEX documents:\documentclass[10pt,final]{article}\usepackage[T1]{fontenc}\usepackage[numbers]{natbib}
This system is a powerful way of controlling
behaviours, but is limited as the options are string
literals. This is perhaps best exemplified by the fontsize options: 10pt, 11pt and 12pt in the standard
classes. Rather than being dimensions parsed andinterpreted, these options are used to load hardcoded configurations for the three nominal sizes.
For the programmer, creating options is easy,requiring only one command for each option, plus aseparate one to process the list of options given by
the user:\DeclareOption{foo}{...}\DeclareOption{bar}{...}\ProcessOptions\relax

As we can see, kvoptions supports ‘strings’ (saving thetokens given in the input), boolean (switch) options
and inverse booleans. It also provides a way to handle
unknown options.
Using kvoptions or similar approaches has allowed programmers to provide key–value options fora number of years. But there are some downsides.
First, ideally one wouldn’t need to load a package
to do this. It would also be better if there was one
mechanism, not several with slightly different syntaxes. More fundamentally, the LATEX kernel carries
out space stripping and expansion of options before
they are passed to packages to examine. This makes
handling some option texts awkward.
There is also the issue of option clashes. The
LATEX kernel checks that the option list of a package
is identical if you try to load it twice:23

LAT X 2

Third-party key–value support

It is natural to want to have a more flexible system,
and key–value methods are the obvious way to obtainthis. As the kernel hasn’t to-date offered this, anumber of third-party packages have been developed
to support programmers in providing these interfaces.
Fundamentally, all of these packages work inthe same way. Keys are defined using an existing
key–value implementation, ready to be used when
the options are examined. A dedicated command isprovided to do the latter, and this examines each
option recorded by LATEX and tries to match it asa key or a key–value pair. If that is possible, thekey–value process is called, while if the option is notknown as a key, an unknown key process is used.
Perhaps the most convenient package for providing key–value options to date is kvoptions, written
by Heiko Oberdiek. Rather than try to provide afull setup for generic key–value work, this package
provides a small set of commands which define themost common types of key–value interface with clear
names:
Joseph Wright, LATEX Project Team
doi.org/10.47397/tb/43-2/tb134wright-keyval\usepackage[option = a]{mypkg}\usepackage[option = b]{mypkg}
This is an issue even without key–value options, butwith them it’s much worse: it’s not possible to know
if there is a true clash or if the settings simply canoverride each other. So there needs to be a way tolet packages themselves handle this.
The new kernel mechanism

In the 2022-06 release of the LATEX kernel, a newbuilt-in approach is available for processing options
using key–value methods. This is based on the expl3
module l3keys, which is nowadays built into the kernel. You don’t, though, need to know anything about
expl3 to use the new approach: everything is madeavailable under standard LATEX 2ε names.
As for the classical approach, we need to do threethings: create options (keys), define how to deal withunknown options, and process the options. Unlike\DeclareOption, the new command \DeclareKeys
can create multiple options in one go. Each option(key) is created by setting one or more properties:
these are given after the key name as .⟨prop⟩. The basic properties are .store, .if and .code. These setup keys, respectively, to store the input, to use it toset a switch or to insert arbitrary code. We can also
set the .default for a key: the value that is assumed
if none is given by the user. We will also be adding.notif for the Fall 2022 release: that will be thesame as kvoptions’ \DeclareComplementaryOption.

TUGboat, Volume 43 (2022), No. 2\DeclareKeys{
name.store= \mypkg@name ,name.default = me,
draft .if
= mypkg@draft ,% final .notif= mypkg@draft ,demo .code=\protected@edef\mypkg@demo{#1}}
To deal with unknown keys, we can declare a dedicated handler: here we simply issue an error.
\DeclareUnknownKeyHandler{%\PackageError{mypkg}{Unknown option "\CurrentOption"}\@ehc}
Finally we need to process the options: the command
name here is pretty simple.
\ProcessKeyOptions
This approach will provide the key–value setup
we want, and the kernel will automatically use thenew approach to repeated loading: there will be
no option clash warnings. We might, though, wantmore control: that can be obtained using the .usage
property:\DeclareKeys{
name .store= \mypkg@name ,name .default = me,name .usage= load,draft .if
= mypkg@draft ,draft .usage= preamble,
demo .code=\protected@edef\mypkg@demo{#1}}With this, the kernel will automatically issue an error
if an option is used in the wrong place: after firstloading for load options, outside of the preamble forpreamble options.

163
4Options are keys

You might have picked up from the above that ‘options’ and ‘keys’ are used almost interchangeably.
That’s because, when processing key–value options,they are simply keys that are created before a callto \ProcessKeyOptions. That means that we canuse options as keys: all we need is a way to set them.
This is available in a command called \SetKeys: you
might notice the name is similar to the long-standing\setkeys from the keyval package.
As most of the time we want to set keys after
loading a package, we need to pass the family thekeys are in. This is given in an optional argument
to \SetKeys. (The optional argument applies toall of the other new commands, but most of thetime we don’t need to worry about it, as LATEX willautomatically use the package or class name.) So wemight have something like
\NewDocumentCommand\mypkgsetup{m}{%\SetKeys[mypkg]{#1}%}
We can then use this new setup command to workwith exactly the same keys as we have created as
options: provided of course we do not try to do thatoutside their usage scope.
5More flexibility

As the new approach is based on l3keys, we can use
any key properties that are defined by l3keys. Thatis because of the fact that options are keys and viceversa: all we need to do is define the keys in theright place.
⋄ Joseph WrightNorthampton, United Kingdom
joseph dot wright (at)morningstar2.co.uk⋄ LATEX Project Team

Key–value setting handling in the LATEX kernel