1

TL;DR

Why is it impossible to set a key in pgfkeys to \pgfkeysnovalue?

\pgfkeys{
  /foo/bar/.initial=\pgfkeysnovalue,
  % ...
  % This will not work
  /foo/bar=\pgfkeysnovalue
}

Main question

I have a problem understanding an issue with pgfkeys. I want to have an option that is resetting itself. I wanted to use the \pgfkeysnovalue macro: If no value is passed to the key, it should be \pgfkeysnovalue, otherwise the corresponding value.

This did not work as expected so I broke it down to an MWE. I put the code below.

Here, /foo is some namespace and /foo/bar is the parameter in question. Using \testCall{} I can add the optional parameter bar=... to set the value for that invocation.

Upon the call, the current value is stored in a macro \mymacro and typed out.

I get the following result when running the MWE:

Result: 
Result: 3
Result: 2
Result: 3
3
Result: 3
Result: 3
Result: 2
Result: 3

Note that the first block is as expected: \pgfkeysnovalue is expanded to the empty string. Then during the first run, the value is reset (here to 3 to show the problem), which is output on the second and fourth lines. In the third line, the default is overwritten.

It is strange that the 3 in the fifth line is output. That should be a pure assignment.

Starting at the sixth line, one would expect the same block to repeat. But the first line of the second block is different, the 3 is still stored in the key, obviously.

When replacing the call to \pgfkeys for the fifth line by \pgfkeyssetvalue as indicated in the comment in the MWE, it works as expected.

Why cannot \pgfkeys be used here?

\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{
    /foo/.is family,/foo,
    bar/.initial=\pgfkeysnovalue,
    call/.code={
        \pgfkeysalso{
            /foo,
            bar/.get=\mymacro,
            % This should be \pgfkeysnovalue but here for sake of presentation some dummy value "3"
            bar=3,
        }
        Result: \mymacro \par
    }
}
\newcommand{\testCall}[1]{\pgfkeys{/foo,#1,call}}
\begin{document}
\testCall{}
\testCall{}
\testCall{bar=2}
\testCall{}

\pgfkeys{/foo/bar=\pgfkeysnovalue}
% \pgfkeyssetvalue{/foo/bar}{\pgfkeysnovalue}

\testCall{}
\testCall{}
\testCall{bar=2}
\testCall{}
\end{document}

1
  • You can define a macro that expands to empty and is (named) different to \pgfkeysnovalue. \pgfkeysnovalue is more or less one of pgfkeys' internal macros hence it's better to not use or rely on it in user code. Feb 8, 2022 at 3:57

1 Answer 1

1

I was just forwarded to this change in the sourcecode of PGF.

It seems that to allow for simpler reading of values, it is now allowed to fetch the value with \pgfkeys{/foo/bar}. The latter is internally parsed as \pgfkeys{/foo/bar=\pgfkeysnovalue} which was redefined as a special case to output the content of the key /foo/bar.

I ended using a dedicated \newif to set a flag if the parameter was to be used or not. Something like this:

\newif\ifbarpresent
\pgfkeys{
  /foo/bar present/.is if=barpresent,
  /foo/bar value/.initial=0,
  /foo/bar/.style={
    /foo/bar present=true,
    /foo/bar value=#1
  }
}

And to use it I did

\ifbarpresent
The value of bar: \pgfkeys{/foo/bar value}
\fi

You must log in to answer this question.

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