1

I've spent about five hours (!) studying How to create a command with key values? (and other resources) and trying to understand how to implement key values and it's been extremely confusing. I have written an essentially trivial (for most people here, anyway) test case and there are some inconsistencies I can't explain.

Here is an MWE using keyval.

% !TEX TS-program = lualatexmk
% !TEX encoding = UTF-8 Unicode

\documentclass{article} \usepackage{keyval}

\makeatletter % Key definitions \define@key{sayhello}{towhom}{\def\sh@towhom{#1}} % Key defaults \setkeys{sayhello}{towhom=Michael} % Define the command that uses the key \newcommand{\sayhello}[2][]{% %\begingroup% localizes the new settings w/o calling the defaults \setkeys{sayhello}{towhom=Michael} % Reset defaults w/o localizing \setkeys{sayhello}{#1} % Set new keys Say hello to \sh@towhom\ #2. %\endgroup% }% \makeatother \begin{document} \sayhello{tomorrow}

%\sayhello[towhom]{today} % throws no value specified for towhom

\sayhello[towhom=Jill]{tomorrow}

%\sayhello[towhom]{today} % throws no value specified for towhom

\sayhello[towhom=Joe]{tomorrow}

%\sayhello[towhom]{tomorrow} % throws no value specified for towhom

\sayhello{today} \end{document}

And here is an MWE using pgfkeys.

% !TEX TS-program = lualatexmk
% !TEX encoding = UTF-8 Unicode

\documentclass{article} \usepackage{pgfkeys}

\pgfkeys{% /sayhello/.is family, /sayhello, towhom/.default=Michael, towhom/.store in=\sayto }%

\newcommand*{\sayhello}[2][]{% \pgfkeys{/sayhello,#1} Say hello to \sayto\ #2. }% \begin{document} %\sayhello{tomorrow} % throws undefined control sequence

\sayhello[towhom]{today}

\sayhello[towhom=Jill]{tomorrow}

\sayhello[towhom]{today}

\sayhello[towhom=Joe]{tomorrow}

\sayhello[towhom]{tomorrow}

\sayhello{today} % works perfectly \end{document}

I was hoping both implementations would give identical results. They do not. keyval doesn't seem to like specifying a key without a value. pgfkeys behaves inconsistently when no options at all are given, but behaves perfectly in the cases where keyval didn't. Are my examples incorrectly coded? Are the inconsistencies expected behaviors? I'm thoroughly confused.

1 Answers1

2

You are mixing up the initial value and default value. The second is used, if you use a key without giving a value. Beside this, if you use a command to store a key value, it is good practice to define it first with \newcommand, as this will avoid that you overwrite existing commands.

Personally I do find pgfkeys more confusing, as with it the same command to define and set keys is used and understanding the behaviour of some handlers isn't always easy, see e.g What do the pgfkeys key handlers .get and .store in do?.

\documentclass{article}
\usepackage{keyval}

\makeatletter \newcommand\sh@towhom{} \define@key{sayhello}{towhom}[Default]{\def\sh@towhom{#1}} \setkeys{sayhello}{towhom=Initial} \newcommand{\sayhello}[2][]{% \begingroup
\setkeys{sayhello}{#1} % Set new keys keyval, say hello to \sh@towhom\ #2. \endgroup% }% \makeatother

\usepackage{pgfkeys}

\newcommand\sayto{} \pgfkeys{% /sayhello/.is family, /sayhello, towhom/.store in=\sayto, towhom/.default=Default, towhom = Initial, }%

\newcommand*{\sayhellopgf}[2][]{% \begingroup \pgfkeys{/sayhello,#1}% pgfkeys, say hello to \sayto\ #2. \endgroup }%

\ExplSyntaxOn \tl_new:N \l_sayhello_towhom_tl \keys_define:nn {sayhello} { towhom .tl_set:N = \l_sayhello_towhom_tl, towhom .initial:n = Initial, towhom .default:n = Default }

\NewDocumentCommand\sayhelloexpl{O{}m} { \group_begin: \keys_set:nn{sayhello}{#1} l3keys,~say~hello~to~\l_sayhello_towhom_tl\c_space_tl#2 \group_end: }

\ExplSyntaxOff \begin{document} \sayhello{tomorrow}

\sayhello[towhom]{today}

\sayhello[towhom=Jill]{tomorrow}

\sayhello[towhom]{today}

\sayhello[towhom=Joe]{tomorrow}

\sayhello[towhom]{tomorrow}

\sayhello{today}

\sayhellopgf{tomorrow}

\sayhellopgf[towhom]{today}

\sayhellopgf[towhom=Jill]{tomorrow}

\sayhellopgf[towhom]{today}

\sayhellopgf[towhom=Joe]{tomorrow}

\sayhellopgf[towhom]{tomorrow}

\sayhellopgf{today}

\sayhelloexpl{tomorrow}

\sayhelloexpl[towhom]{today}

\sayhelloexpl[towhom=Jill]{tomorrow}

\sayhelloexpl[towhom]{today}

\sayhelloexpl[towhom=Joe]{tomorrow}

\sayhelloexpl[towhom]{tomorrow}

\sayhelloexpl{today} \end{document}

enter image description here

Ulrike Fischer
  • 327,261
  • THANK YOU so much for this informative and complete answer! keyval seems the simplest, but I like the elegance of l3keys. – LaTeXereXeTaL Nov 04 '20 at 22:58