Discussion:
Keyvals
Peter Flynn
2018-01-10 21:53:28 UTC
Raw Message
I am having severe problems understanding any/all of the keyval-related
packages — as predicted by Wright and Feuersänger (2009).

I want an option to a package for specifying a postgraduate degree like
this:

\documentclass{article}
\usepackage[degree=ma]{test}
\begin{document}
This is a degree of \printdegree
\end{document}

Here is test.sty

\RequirePackage{xkeyval}
\newcounter{degreeindex}
\***@choicekey+*{U}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}
{\gdef\degreetype{#1}}
\ProcessOptionsX
\setkeys{U}{degree}
\ifcase\***@degreeindex
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype (\degreename)}

However, this produces the error:

! LaTeX Error: Unknown option degree' for package test'.

which makes no sense. It continues

l.15 \setkeys
{U}{degree}

! Package xkeyval Error: degree' undefined in families U'.

Clearly I have misunderstood the documentation, which is deeply
confusing. Does anyone know how to implement a list-option type of key?

///Peter
Holger Schieferdecker
2018-01-11 09:45:02 UTC
Raw Message
Hello Peter,
Post by Peter Flynn
I am having severe problems understanding any/all of the keyval-related
packages — as predicted by Wright and Feuersänger (2009).
First I need to say that I never used keyval or xkeyval before, but I
was curious. I made a little progress with your example, but it is still
not working as intended. But I noticed two issues:

1. The order of +* after \***@choicekey seems to be wrong. According
to the documentation it should be \***@choicekey*+

2. A key needs a default value, see documentation of xkeyval (section
3.1: xkeyvalwill generate an errorwhen the user omits =value...). This
can be specified either in the declaration of the choicekey or in the
\setkeys part.

As I changed that now your example compiles without error, but
unfortunately the output is always the default value :-(

Another thin I needed to change was to call \ProcessOptionsX<U>
specifying the family. I thought that should not be necessary.

So even if I don't have a solution maybe this will help a little bit.

Holger

%--- modified example ---
\RequirePackage{xkeyval}
\newcounter{degreeindex}
\***@choicekey*+{U}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}
% [phd]
{\gdef\degreetype{#1}}
\ProcessOptionsX<U>
\setkeys{U}{degree=phd}
\ifcase\***@degreeindex
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype\ (\degreename)}
%---
Post by Peter Flynn
I want an option to a package for specifying a postgraduate degree like
\documentclass{article}
\usepackage[degree=ma]{test}
\begin{document}
This is a degree of \printdegree
\end{document}
Here is test.sty
\RequirePackage{xkeyval}
\newcounter{degreeindex}
{phd,ma,msc}
{\gdef\degreetype{#1}}
\ProcessOptionsX
\setkeys{U}{degree}
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype (\degreename)}
! LaTeX Error: Unknown option degree' for package test'.
which makes no sense. It continues
l.15 \setkeys
{U}{degree}
! Package xkeyval Error: degree' undefined in families U'.
Clearly I have misunderstood the documentation, which is deeply
confusing. Does anyone know how to implement a list-option type of key?
///Peter
Holger Schieferdecker
2018-01-11 13:17:02 UTC
Raw Message
Post by Holger Schieferdecker
As I changed that now your example compiles without error, but
unfortunately the output is always the default value :-(
Ok, now I changed the order of \setkeys and \ProcessOptionsX, and
finally the example document reacts on the specified degree.

Holger

%---
\RequirePackage{xkeyval}
\newcounter{degreeindex}
\***@choicekey*+{U}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}
% [phd]
{\gdef\degreetype{#1}}
\setkeys{U}{degree=phd}
\ProcessOptionsX<>
\ifcase\***@degreeindex
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype\ (\degreename)}
Peter Flynn
2018-01-30 21:38:20 UTC
Raw Message
Post by Holger Schieferdecker
Post by Holger Schieferdecker
As I changed that now your example compiles without error, but
unfortunately the output is always the default value :-(
Sorry for the delay in responding.

Thanks for all your work on this. I've worked in IT all my life, and had
to deal with documentation from many sources, and I must confess the
documentation for all the keyval packages is the most impenetrably
difficult I have ever encountered. A major task for me for 2018 is to
write something to fix this. But first, that means understanding how it
works :-)
Post by Holger Schieferdecker
Ok, now I changed the order of \setkeys and \ProcessOptionsX, and
finally the example document reacts on the specified degree.
Yes, that works perfectly...but see next post :-)

///Peter
Post by Holger Schieferdecker
%---
\RequirePackage{xkeyval}
\newcounter{degreeindex}
{phd,ma,msc}
%                   [phd]
{\gdef\degreetype{#1}}
\setkeys{U}{degree=phd}
\ProcessOptionsX<>
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype\ (\degreename)}
Nicola Talbot
2018-01-11 13:15:03 UTC
Raw Message
Post by Peter Flynn
I am having severe problems understanding any/all of the keyval-related
packages — as predicted by Wright and Feuersänger (2009).
I want an option to a package for specifying a postgraduate degree like
\documentclass{article}
\usepackage[degree=ma]{test}
\begin{document}
This is a degree of \printdegree
\end{document}
Here is test.sty
\RequirePackage{xkeyval}
\newcounter{degreeindex}
{phd,ma,msc}
{\gdef\degreetype{#1}}
\ProcessOptionsX
\setkeys{U}{degree}
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
\newcommand{\printdegree}{\degreetype (\degreename)}
! LaTeX Error: Unknown option degree' for package test'.
which makes no sense. It continues
l.15 \setkeys
{U}{degree}
! Package xkeyval Error: degree' undefined in families U'.
Clearly I have misunderstood the documentation, which is deeply
confusing. Does anyone know how to implement a list-option type of key?
When you use xkeyval to define package options, the family name must
match the package name (including extension). Modified test.sty:

\RequirePackage{xkeyval}
\newcounter{degreeindex}
\newcommand{\degreetype}{??}
\newcommand{\degreename}{??}
\***@choicekey*+{test.sty}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}
{%
\gdef\degreetype{#1}%
\ifcase\***@degreeindex
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
}
\ProcessOptionsX
\newcommand{\printdegree}{\degreetype (\degreename)}

(Similarly if the code is in a class file test.cls then the family name
must be test.cls.) This way the package option is correctly picked up
and processed by \ProcessOptionsX.

Regards
Nicola Talbot
--
Home: http://www.dickimaw-books.com/
Creating a LaTeX Minimal Example:
http://www.dickimaw-books.com/latex/minexample/
Peter Flynn
2018-01-30 21:46:49 UTC
Raw Message
[snip]
Post by Nicola Talbot
When you use xkeyval to define package options, the family name must
match the package name (including extension).
Thank you for this and the code. I had missed that point, except that it
seems to work with the value U as in Holger's corrected example.
Post by Nicola Talbot
\RequirePackage{xkeyval}
\newcounter{degreeindex}
\newcommand{\degreetype}{??}
\newcommand{\degreename}{??}
{phd,ma,msc}
No default value? If I add [phd] here it doesn't use it. Using the two
\newcommand statements would work, but I had hoped that xkeyval would
have a way to implement defaults.
Post by Nicola Talbot
{%
\gdef\degreetype{#1}%
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
}
It certainly works putting the mapping here (not that it would ever have
occurred to me to do so :-) Is this the normal place to do this?
Post by Nicola Talbot
\ProcessOptionsX
No <test.sty>? Holger implied that it was compulsory.
Post by Nicola Talbot
\newcommand{\printdegree}{\degreetype (\degreename)}
(Similarly if the code is in a class file test.cls then the family name
must be test.cls.) This way the package option is correctly picked up
and processed by \ProcessOptionsX.
That is a truly weird requirement, but as I still haven't grokked what a
family name is FOR, that's probably just me being weird. What happens if
you need half a dozen families?> They surely can't all be called after
the filename...

///Peter
Holger Schieferdecker
2018-01-31 09:19:54 UTC
Raw Message
Post by Peter Flynn
[snip]
Post by Nicola Talbot
When you use xkeyval to define package options, the family name must
match the package name (including extension).
Well, I wouldn't say 'must', but it's definitely the easiest way.
Post by Peter Flynn
Thank you for this and the code. I had missed that point, except that it
seems to work with the value U as in Holger's corrected example.
Digging deeper into it I understand that using the package name as
family name is of advantage because other commands use that as default
value. If one uses a different family name one has to take care of that.
See below.
Post by Peter Flynn
Post by Nicola Talbot
\RequirePackage{xkeyval}
\newcounter{degreeindex}
\newcommand{\degreetype}{??}
\newcommand{\degreename}{??}
{phd,ma,msc}
No default value? If I add [phd] here it doesn't use it. Using the two
\newcommand statements would work, but I had hoped that xkeyval would
have a way to implement defaults.
Post by Nicola Talbot
{%
\gdef\degreetype{#1}%
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
}
It certainly works putting the mapping here (not that it would ever have
occurred to me to do so :-) Is this the normal place to do this?
Post by Nicola Talbot
\ProcessOptionsX
No <test.sty>? Holger implied that it was compulsory.
It seems that I start understanding xkeyval slightly better the more I

If you used the package name as family name you can omit the family name
here because \ProcessOptionsX uses the package name as default. See
documentation section 7. It is only compulsory if you used a different
family name.
Post by Peter Flynn
Post by Nicola Talbot
\newcommand{\printdegree}{\degreetype (\degreename)}
(Similarly if the code is in a class file test.cls then the family
name must be test.cls.) This way the package option is correctly
picked up and processed by \ProcessOptionsX.
That is a truly weird requirement, but as I still haven't grokked what a
family name is FOR, that's probably just me being weird. What happens if
you need half a dozen families? They surely can't all be called after
the filename...
I can only guess here, but besides the prefix the family name is an
additional way to use keys with the same name. The documentation states
that the default prefix is KV. Maybe this helps to interact with other
packages which are using keyval and not xkeyval.

As I'm not familiar with all that stuff I can't tell if it's useful to
have keys with different families in one package.

The advantage of not using the filename as family is that if you change
your filename during development of the class/package you don't have to
change all the family names as well.

Holger
Nicola Talbot
2018-01-31 15:03:12 UTC
Raw Message
Post by Peter Flynn
[snip]
Post by Nicola Talbot
When you use xkeyval to define package options, the family name must
match the package name (including extension).
Thank you for this and the code. I had missed that point, except that it
seems to work with the value U as in Holger's corrected example.
Sorry, I'd completely forgotten that \ProcessOptionsX has optional
arguments. I have a tendency to just copy the option processing code
from one of my existing packages when I start a new package.
Post by Peter Flynn
Post by Nicola Talbot
\RequirePackage{xkeyval}
\newcounter{degreeindex}
\newcommand{\degreetype}{??}
\newcommand{\degreename}{??}
{phd,ma,msc}
No default value? If I add [phd] here it doesn't use it. Using the two
\newcommand statements would work, but I had hoped that xkeyval would
have a way to implement defaults.
The default value, as used below, is if 'degree' is used without a value:

\***@choicekey*+{test.sty}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}[phd]
{%
\gdef\degreetype{#1}%
\ifcase\***@degreeindex
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
}

This means that \usepackage[degree]{test} is equivalent to
\usepackage[degree=phd]{test}.


\newcommand{\degreetype}{phd}
\newcommand{\degreename}{Doctor of Philosophy}
\***@choicekey*+{test.sty}{degree}
[\degreetype\***@degreeindex]
{phd,ma,msc}[phd]
{%
\renewcommand\degreetype{#1}%
\ifcase\***@degreeindex
\renewcommand\degreename{Doctor of Philosophy}\or
\renewcommand\degreename{Master of Arts}\or
\renewcommand\degreename{Master of Science}\fi
}

It's safer this way. If you don't initialise with \newcommand then you
need to use \ExecuteOptionsX to set up the defaults before processing
the options.
Post by Peter Flynn
Post by Nicola Talbot
{%
\gdef\degreetype{#1}%
\gdef\degreename{Doctor of Philosophy}\or
\gdef\degreename{Master of Arts}\or
\gdef\degreename{Master of Science}\fi
}
It certainly works putting the mapping here (not that it would ever have
occurred to me to do so :-) Is this the normal place to do this?
That's where I usually put it, but I don't know if that's normal for
anyone else :-)
Post by Peter Flynn
Post by Nicola Talbot
\ProcessOptionsX
No <test.sty>? Holger implied that it was compulsory.
No, I've never used \ProcessOptionsX with an argument. The xkeyval
document states that both [arg] and <arg> are optional in section 7
(package option processing).
Post by Peter Flynn
Post by Nicola Talbot
\newcommand{\printdegree}{\degreetype (\degreename)}
(Similarly if the code is in a class file test.cls then the family
name must be test.cls.) This way the package option is correctly
picked up and processed by \ProcessOptionsX.
That is a truly weird requirement, but as I still haven't grokked what a
family name is FOR, that's probably just me being weird. What happens if
you need half a dozen families?> They surely can't all be called after
the filename...
Sorry, my mistake. If you don't use the file name for the family (when
declaring class/package option keys) then you need to specify the family
in \ProcessOptionsX (and presumably in commands like \DeclareOptionX).

I actually quite like using the file name for the package/class options
as it makes it more obvious which are the package/class options when
quickly glancing through the code, but mostly because it helps to reduce
conflict with other packages which might happen to coincidentally share
the same option names. Using the file name as the family ensures they
don't clash. (At least, it's highly unlikely that a user will try to
load two packages with the same file name in different locations.) A
short family name (such as U) is far less likely to be unique.

However, I use different family names for other keys (that aren't used
as package options). For example, in glossaries.sty the 'toc' package
option is defined as:

\***@boolkey{glossaries.sty}[gls]{toc}[true]{}

but the 'type' key used in the optional argument of \printglossary is
defined as:

\***@key{printgloss}{type}{\def\@***@type{#1}}

In this case I base the family name on the command name (or a shortened
version of it) for clarity (and again it helps to reduce the chances of
clashing with another package that happens to provide the same key name).

Sometimes I have keys with the same name for package options and for
commands, but the different family helps to separate them (so one
setting is used globally and the other locally). For example, package
option 'sort':

\***@choicekey{glossaries.sty}{sort}{standard,def,use,none}{%
\renewcommand*{\@***@default@sorttype}{#1}%
\csname @***@setupsort@#1\endcsname
}

Whereas 'sort' for use with \printnoidxglossary:

\***@key{printgloss}{sort}{\@***@assign@sortkey{#1}}

The options have the same name, but behave differently depending on use.

Regards
Nicola Talbot
--
Home: http://www.dickimaw-books.com/
Creating a LaTeX Minimal Example:
http://www.dickimaw-books.com/latex/minexample/
Peter Flynn
2018-01-31 19:04:44 UTC
Raw Message
On 31/01/18 09:19, Holger Schieferdecker wrote:
[...]
Post by Holger Schieferdecker
If you used the package name as family name you can omit the family
name here because \ProcessOptionsX uses the package name as default.
See documentation section 7. It is only compulsory if you used a
different family name.
OK, got that now.
Post by Holger Schieferdecker
What happens if you need half a dozen families? They surely can't
all be called after the filename...
I can only guess here, but besides the prefix the family name is an
additional way to use keys with the same name. The documentation
states that the default prefix is KV. Maybe this helps to interact
with other packages which are using keyval and not xkeyval.
As I'm not familiar with all that stuff I can't tell if it's useful
to have keys with different families in one package.
Right. I'm trying to think of a use case and I can't.
Post by Holger Schieferdecker
The advantage of not using the filename as family is that if you
change your filename during development of the class/package you
don't have to change all the family names as well.
That would certainly be a big advantage; and also if you want to use a
particular subset (family?) of keys in a completely different package.

I'm still unclear what "families" are for.
[...]
Post by Holger Schieferdecker
No default value? If I add [phd] here it doesn't use it. Using the
two \newcommand statements would work, but I had hoped that xkeyval
would have a way to implement defaults.
[snip]> This means that \usepackage[degree]{test} is equivalent to
Post by Holger Schieferdecker
\usepackage[degree=phd]{test}.
I would have to disagree. That is not what people mean by a default. A
default is what happens when you omit *the entire key*, not when you
provide the key without a value (except in the case of Boolean keys).

\usepackage{test} should default to the degree being 'phd'. I don't
think anyone would ever think of using \usepackage[degree]{test}.
Absolutely. But it's a pity that xkeyval doesn't provide for defaults
when the user omits the key completely.
Post by Holger Schieferdecker
It's safer this way. If you don't initialise with \newcommand then you
need to use \ExecuteOptionsX to set up the defaults before processing
the options.
Yep.
Post by Holger Schieferdecker
I actually quite like using the file name for the package/class options
as it makes it more obvious which are the package/class options when
quickly glancing through the code, but mostly because it helps to reduce
conflict with other packages which might happen to coincidentally share
the same option names. Using the file name as the family ensures they
don't clash. (At least, it's highly unlikely that a user will try to
load two packages with the same file name in different locations.) A
short family name (such as U) is far less likely to be unique.
Yes, good reasons. The U was just for brevity in testing. In realist it
would be the abbreviation of the institution, or the application.
Post by Holger Schieferdecker
However, I use different family names for other keys (that aren't used
as package options).
Ahh. <sound of light dawning>
Post by Holger Schieferdecker
The options have the same name, but behave differently depending on use.
Thank you for this, it's a lot clearer now :-)

P