Key-value input for macros and package options

When we discussed extending the number of arguments to a macro, we suggested that large numbers of arguments, distinguished only by their position, aren't very kind to the user, and that a package such as keyval offers a more attractive user interface. We now consider the packages that the macro programmer might use, to create such a user interface.

The simplest key-value processor (for LaTeX, at least) remains keyval; it has a command \define@key to declare a key and a handler to process it, and a macro \setkeys to offer values to the handler of one or more keys. Thus:

\define@key{my}{foo}{Foo is #1\par}
\define@key{my}{bar}[99]{Bar is #1\par}
...
\setkeys{my}{foo=3,bar}

will produce output saying:

Foo is 3
Bar is 99

This has defined two keys foo and bar in family my, and then executed them, the first with argument 3 and the second with no argument, so that the default value of 99 is picked up. In effect, the two calls to \define@key are simply defining commands, as (for example):

\newcommand{\KV@my@foo}[1]{Foo is #1}

(the definition of \KV@my@bar is similar, but trickier). The command \setkeys knows how to find those commands when it needs to process each key — it is easy to regurgitate the structure of the command name, with family name (my, here) after the first @, and the key name after the second @. (The KV part is fixed, in keyval.)

These simple commands are enough, in fact, to process the botanical example offered as replacement for multi-argument commands in the question mentioned above, or the optional arguments of the \includegraphics command of the graphicx package. (The last is, in fact, what keyval was designed to do.)

However, we need more if we're to to have package options in “key-value” form. Packages like hyperref have enormously complicated package options which need key-value processing at \ProcessOptions time: keyval can't do that on its own.

Heiko Oberdiek's kvoptions package comes to our help: it enables the programmer to declare class or package options that operate as key and value pairs. The package defines commands \DeclareBoolOption for options whose value should be either true or false, and \DeclareStringOption for all other options that have a value. Keys are declared using keyval and may remain available for use within the document, or may be “cancelled” to avoid confusion. If you have loaded kvoptions, the LaTeX kernel's \DeclareOption becomes \DeclareVoidOption (it's an option with no value), and \DeclareOption* becomes \DeclareDefaultOption.

Heiko also provides kvsetkeys which is a more robust version of setkeys, with some of the rough edges made smoother.

Hendri Adriaens' xkeyval offers more flexibility than the original keyval and is more robust than the original, too. Like kvoptions, the package also has mechanisms to allow class and package options in key-value form (macros \DeclareOptionX, \ExecuteOptionsX and \ProcessOptionsX. Pstricks bundle packages use a xkeyval derivative called pst-xkey for their own key-value manipulation.

The (widely-respected) pgf graphics package has its own key-value package called pgfkeys. The documentation of the package (part of the huge pgf manual, in part 5, “utilities”) contains a useful comparison with other key-value systems; some notable differences are:

Keys are organized in a tree that is reminiscent of the Unix fille tree. A typical key might be, /tikz/coordinate system/x or just /x. When you specify keys you can provide the complete path of the key, but you usually just provide the name of the key (corresponding to the file name without any path) and the path is added automatically. So a \pgfkeys command might be:

\pgfkeys{/my key=hello,/your keys/main key=something\strange,
  key name without path=something else}

and for each key mentioned, the associated code will be executed. … and that code is also set up using \pgfkeys:

\pgfkeys{/my key/.code=The value is "#1".}

after which

\pgfkeys{/my key=hi!}

will produce just

The value is "hi!".

The manual goes on, showing how to define a key with two arguments, how to provide default value for a key, and how to define aliases for particular key sequences (which are called “styles”). All in all, it seems a well thought-out system, offering a lot of flexibility that isn't available with the other keys packages. However, there seems to be no mechanism for using pgfkeys keys as part of the options of another package, in the way that kvoptions does.

The l3kernel programming layer for LaTeX3 includes the l3keys module. Inspired by pgfkeys, it provides a keyval-based method for the programmer to create keys. As with keyval and derivatives, l3keys uses separate macros for defining and setting keys. The package l3keys2e makes it possible for LaTeX2e class and package options to be processed using l3keys. L3kernel code can be used within existing LaTeX2e documents, so l3keys is also available to the LaTeX2e programmer “direct”.

Another key-value system that's part of larger set of macros is scrbase, which uses the facilities of keyval to build a larger set of facilities, originally for use within the KOMA-script bundle. For English-speaking authors, there are difficulties from the German-only documentation; however, from a partial translation available to the author of this answer, a summary is possible. The package may build on the facilities either of keyval or of xkeyval, and builds its functionality on the structure of the “key family”. The user may define family “members” and keys are defined relative to the members. (For example, the package scrbase is part of the KOMA-script bundle; so its keys are all members of the scrbase.sty family within the KOMA family. The function \FamilyProcessOptions allows the programmer to decode the options of the package in terms of the package's key family. Note that there is no special provision made for “traditional” package options, as in the kvoptions package.

This brief summary was guided by input from two sources: a draft article for TUGboat by Joseph Wright, and the partial translation of the documentation of package scrbase prepared by Philipp Stephani.

All the above are (at least) aimed at LaTeX programming; there is one package, getoptk, aimed at the Plain TeX programmer. Getoptk uses syntax inspired by that offered by TeX primitives such as \hrule and \hbox, so we are offered syntax such as:

\begindisplay file {chapter1} literal offset 20pt

(taken from the package manual).

There are (we know) people who would swear that such syntax is wonderful (the present author wouldn't), but the package earns its place as the only stand-alone key-value macros that will work in Plain TeX.


Source: Key-value input for macros and package options