21

The excellent pgfkeys package provides, among others, two kinds of keys: regular "value-centric" keys that can be declared with /.initial, and "macro-centric" keys are declared with /.store in. Here is an example declaration of two keys:

\newcommand*{\mystoragemacro}{}
\pgfkeys{
  my vkey/.initial = <initial value>,
  my mkey/.store in = \mystoragemacro,
  my mkey = <initial value>}

Setting the two types of keys is done as usual:

\pgfkeys{my vkey = <value>, my mkey = <value>}

However, code that retrieves the values stored in these keys works differently depending on the type of key. For .initial keys, the value is retrieved with \pgfkeysvalueof (e.g., \pgfkeysvalueof{my vkey}); for .store in keys, the value is always available in the storage macro (e.g., \mystoragemacro).

Question: What are the advantages and disadvantages of these two kinds of keys? When should I use a .initial key, and when should I use a .store in key?

As a concrete instance of my question, why did Ryan Reich use .store in keys in his \myparbox example, instead of using .initial keys?

0

2 Answers 2

14

My personal preference is to avoid using .store in keys at all, with the following exception:

A .store in key is required when using pgfkeys as an interface to an existing system that doesn't use it.

For example, suppose that you wanted, in the course of your key-processing, to alter the material that would be printed by \ref if it pointed to a \label that was called right afterward, i.e.

\pgfkeys{ref text = xyz}
\label{after key}
\ref{after key}% Prints "xyz"

This material is stored (in some fashion) using the \@currentlabel macro, which is a LaTeX2e kernel internal macro. Thus, you could achieve this effect by declaring ref text as something like

\pgfkeys{ref text/.store in = \@currentlabel}

Other than this, I think it's a waste of effort to concoct a personal namespace, have to slog through its obfuscation, and in the end duplicate the action of \pgfkeysvalueof. There is one disadvantage to using .initial keys together with this macro: although it expands to \pgfk@<key>, it does so after two layers of indirection: first, expanding \pgfkeysvalueof, and second, expanding the resulting \csname, only after which does the actual macro name hit the input stream. I.e., it looks like

\pgfkeysvalueof{<key>}
-> \csname pgfk@<key>\endcsname
-> \pgfk@<key>

This makes it really awkward to manipulate this key as a macro; e.g. if you wanted to make a shortcut, say \let\mymacro<whatever underlies "key">, you can't do

% Makes \mymacro = \pgfkeysvalueof
\let\mymacro\pgfkeysvalueof{<key>}

nor can you do the usual (ugly) workaround

% Makes \mymacro = \csname
\expandafter\let\expandafter\mymacro\pgfkeysvalueof{<key>}

but you either have to do two runs of \expandafter:

\expandafter\expandafter\expandafter\let
\expandafter\expandafter\expandafter\mymacro
\pgfkeysvalueof{<key>}

(which is bad in so many ways, first among them that you shouldn't have to know how \pgfkeysvalueof expands), or you have to just know that the macro is actually just \pgfk@<key> (which is bad because it's exposing the internal representation of an abstraction).

But you don't want to do this; if you do, then you are misusing pgfkeys. Instead, if you work within the system you can use .get:

\pgfkeys{<key>/.get = \mymacro}

which does the last thing mentioned above (but now it's good because it's pgfkeys itself that uses its own internal representations). I don't think there's a quick way to copy one key to another key, however; the .link handler functions like \def rather than \let, while the \pgfkeyslet{<key>}<macro> macro copies a macro to a key. Here's a handler that does that:

% Uses `etoolbox` for brevity
\pgfkeys{/handlers/.let/.code = {%
  \csletcs{pgfk@\pgfkeyscurrentpath}{pgfk@#1}%
  \csletcs{pgfk@\pgfkeyscurrentpath/.@cmd}{pgfk@#1/.@cmd}%
}}

Whether or not this is evil is a matter of ego, I suppose, if writing in the /handlers namespace makes one a pgfkeys developer.

Finally, there is a related drawback to using .initial + \pgfkeysvalueof, namely that you can't easily \expandafter the resulting macro and there really isn't a way around that. That is, if you use .initial to store some content that acts like a macro with arguments and you want to both use the key as a macro and store the arguments in another macro, you will have trouble. Say, for example, a key that imitates \section:

\pgfkeys{section key/.initial = \section}
% \optarg is either empty or contains [...] material
\pgfkeysvalueof{section key}\optarg\mandarg

(which is really sort of pointless but serves as an example): this will just not work, because \section needs its optional argument to look like one. So you would normally write

\expandafter\section\optarg\mandarg

and all would be well. Unfortunately, the same does not work with section key:

% Actually does nothing at all
\expandafter\pgfkeysvalueof{section key}\optarg\mandarg

As before, sufficiently many \expandafters would work, but there really does not exist a single operation that jumps over an entire block of code to expand the next token, so you are in for a mess. And yet this all would be easy if you just used .store in:

\pgfkeys{section key/.store in = \sectionkey}
\pgfkeys{section key = \section}
% No problem
\expandafter\sectionkey\optarg\mandarg

Since pgfkeys is an object-oriented language, I consider it a feature that it makes it difficult to operate as a macro language even when it does deign to provide an interface to the one it's written in.

Anyway, if you are going to use macros it's clearly more (time) efficient to .store in them. Since no one has ever really succeeded in hiding the basic nature of TeX from all programming activities, it's always necessary at some point to do something dirty, and the question is when. I believe these are the only times one would need to actually leave the pgfkeys walled garden.

3
  • Nice read! Though I have to confess I was expecting a yet-another trace-pgfkeys wizardry :) One minor addition might be that \pgfkeyslet{<key>}{<macro name>} is already present.
    – percusse
    Jul 24, 2013 at 9:59
  • Thanks for the excellent answer! I didn't follow the first sentence of your second to last paragraph ("Finally, there is..."). If you have time, could you maybe add an example? Also, I'd be interested in any comment you have on why you chose .store in keys for the \myparbox example from your popular "gentle intro to pgfkeys" answer. Thanks again! Jul 24, 2013 at 20:44
  • @HenryDeYoung Thank you! I expanded on the \expandafter comment. As for my other answer, I should say first that my philosophy has continued to develop since then so I don't know exactly what I was thinking, but I can justify it a postiori as doing exactly what I advised here: using macros as an interface to an existing command that doesn't use keys. See, the various .store in keys allow you to enter info as key-values, but retrieve it in a way that \parbox can use.
    – Ryan Reich
    Jul 24, 2013 at 21:51
12

Value keys (created by the /.initial handler) save the value in a macro named \pgfk@<full path to key>. Most used examples probably include the keys minimum width, minimum height as well as the inner and outer separations that are read very often while PGF constructs a node. Besides directly using \csname pgfk@<full path to key> they can be accessed in the following ways:

  • \pgfkeysvalueof{<full path to key>}:

    This is simply a wrapper for the \csname access and is expandable (as long as the content is expandable of course).

  • \pgfkeysgetvalue{<full path to key>}<macro>:

    This saves the content of the key in <macro>. This is done with the \let macro.

  • key/.get=<macro>:

    Similar to \pgfkeysgetvalue, the /.get handler saves the content of the key it is used on in <macro>. The difference to \pgfkeysgetvalue is that it can be used inside of \pgfset, \tikzset or similar \pgfkeys arguments and thus, the use doesn’t need to be aware of the full and correct path. It is also possible to do

    \pgfkeys{/tikz/my value/.initial=7}
    \tikzset{my value/.get=\myValue}
    

    without having to prepend /tikz/. Of course, if this is needed more often, you could simply define

    \def\tikzgetvalue#1{\pgfkeysgetvalue{/tikz/#1}}
    

    for that.

  • \pgfkeys{<full path of key>}:

    If there is no /.default value stored for the value key, one can also access the value by simply using the key name without an =. Though, this is not expandable (and thus cannot be used for PGF math).

    This makes it also possible to “get” the values of keys like minimum width, minimum height and the separators as they are actually belong to the /pgf path. (The /.get handler neither checks for a defined key nor does it check any of the /.search also paths.)

If the key (or the key path) is known to the user they can use it without knowing where the value is actually stored.


For a /.store in (or similar keys) the value of the key (i.e. the value of the macro) is not directly accessible to the user, even though, the macro might be just \mystoragemacro and thus easily usable (without \makeatletter or \csname).

A /.store in key creates a little bit overhead as two macros are used to store one value:

  1. The actual macro that stores the value, say \mystoragemacro; and
  2. the macro that is used by the key, say \pgfk@/tikz/my value/.@cmd.

Without \newcommand*{\mystoragemacro}{} and my mkey = <initial value>, a /.store in key can be considered never-defined/never-used-by-the-user. (Although you could change that: How do you test whether a known key value has been set in pgfkeys.)


A /.initial key needs (more or less) to be get first before it can be used (if you consider \mystoragemacro and \pgfkeysvalueof{<full path to key>} that much different, the second one needs only to expanded twice and has then the same state as \mystoragemacro).

If you are working with the values of a lot of /.initial keys you might consider “getting” them in easier accessible macro names via \pgfkeysgetvalue. If they contain a mathematical expression it might be more efficient to let PGF math run over them before saving them in a macro.


Conclusion: Convenience.

A /.store in key value might be easier to access if you need it. I consider an /.initial key more flexible and more accessible, especially for TikZ where most thinks are thrown into PGF math anyway.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .