Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The following screen shot shows how the order of specified key-values affects the output.

  1. When using dx=\psPiH,xunit=\psPi.

    enter image description here

  2. When using xunit=\psPi,dx=\psPiH.

    enter image description here

Minimal Working Example

\documentclass[pstricks]{standalone}
\usepackage{pst-plot}

\psset{trigLabels=true,trigLabelBase=2,}

\begin{document}

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[dx=\psPiH,xunit=\psPi](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}


\begin{pspicture}(-7,-2)(7,2)
    \psaxes[xunit=\psPi,dx=\psPiH](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}


\end{document}

It might be a bug. But does the order of specified key-values matter?

share|improve this question
10  
I think you answered the question, in general the order does matter. Certainly in the keyval system used by the graphicx package (and pstricks is very similar) they explicitly are evaluated in order (so that keys specifying scaling and rotation and origin offsets have a defined meaning if used together) –  David Carlisle Jul 25 '12 at 13:51
    
While the example here is PStricks-based, the question itself seems entirely general. Would removing the pstricks tag be appropriate? –  Joseph Wright Aug 3 '12 at 11:09
add comment

4 Answers

up vote 22 down vote accepted
+50

In general, the order of keys does matter where there is some interaction between the keys. That is because keys are normally processed in a left-to-right sense, and so the settings from the 'earlier' keys can be altered by those 'later' in the list.

There are cases where internally implementations use multiple pass approaches to setting keys. This is done for example by fontspec, which first checks basic detail of font in use before setting keys which make sense for that type.

It is possible to set up key-value methods such that order does not matter, for example by parsing them into an array which is then used in a fixed order. However, that is not something which most packages do, and would I hope be documented by any package using this method.

share|improve this answer
add comment

The order is only important if the keys depend to each other. dx is a PSTricks length and it can be used with or without a unit. Without a unit it takes the current value of psxunit into account! And that value is set by the key xunit. That is the expected behaviour of a relative length setting!

Using dx with an absolute length (has a unit like \psPiH cm) makes both keys independent:

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[dx=\psPiH cm,xunit=\psPi](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[xunit=\psPi,dx=\psPiH cm](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}

will give the same output!

share|improve this answer
add comment

Although any key-value system gives the appearance of "setting properties" of some kind (for example, the numerical parameters of a picture), in fact to some extent they are all "calling methods" instead. I really only know about pgfkeys, which is not what you're asking about, but in that system, keys are as powerful as TeX macros and, therefore, can have arbitrarily complicated behavior. As Herbert answers, even for your example one key sets a default that is used by another key, and this is something you can expect to matter even for keys that basically just set properties.

It would be possible, as a programming question unrelated to TeX, to make the keys independent of order, which would involve setting a flag for each key and storing its value before actually acting on it. At the end of the list, one checks all the flags and resolves all interactions via numerous conditional statements, and finally uses the requested values in whatever way is implied by the keys in the list as a whole. Since this involves manually verifying all possible combinations of keys, and in the end is basically just establishing a default order (as in Joseph's answer), it is easier just to let the given order be the default, which is what is actually done.

share|improve this answer
add comment

Rearranging the order of setting keys internally (from a user key-value list) will be expensive. Setting the list twice may make the order of the list less relevant, but the key author has to exercise some caution.

Let us assume the following keys.

\mp@a depends on \mp@b that comes later, so we have to make the evaluation of \mp@a conditional on knowing \mp@b:

\define@key{fam}{a}[1cm]{%
  \ifdefined\mp@b\edef\mp@a{\the\dimexpr#1+\mp@b}\fi
}
\define@key{fam}{b}[.5cm]{\def\mp@b{#1}}

The updated value of \mp@a will not be known until key b has been set.

Setting the list twice will make the order of the list less relevant. This can be achieved via the following

\newcount\setkeyscount
\def\setkeystwice{\@testopt\s@tkeystwice{KV}}
\def\s@tkeystwice[#1]#2#3{%
  \setkeyscount\z@
  \loop
    \setkeys[#1]{#2}{#3}%
    \advance\setkeyscount\@ne
    \ifnum\setkeyscount<\tw@
   \repeat
}

\setkeystwice{a=1cm,b=2cm}

Here is a more formal approach, which requires no special conditionals in defining the keys. The key author only needs to call \orderofkeys with the right order of how he wants the keys to be set internally. Note that (i) \orderofkeys (actually, \XKV@setheadkeys) does not filter out 'current keys' (i.e., keys appearing in the user-supplied key-value list) from its preset list; and (ii) \orderofkeys takes a key-value list but the user can omit values for keys with default values.

\documentclass{article}
\usepackage{xkeyval}
\makeatletter
\newcommand*\headkeys{\XKV@stfalse\XKV@testoptb\XKV@headkeys}
\def\XKV@headkeys#1{\XKV@pr@setkeys{#1}{headkeys}}
\let\orderofkeys\headkeys

% \setkeystwice[<pref>]{<fam>}[<na>]{<kvlist>}
\def\setkeystwice{\XKV@testopta{\XKV@testoptc\XKV@setkeystwice}}
\def\XKV@setkeystwice[#1]#2{%
  \ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
  \XKV@checksanitizea{#2}\XKV@tempb
  \let\XKV@naa\@empty
  \XKV@for@o\XKV@tempb\XKV@tempa{%
    \expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
    \XKV@addtolist@x\XKV@naa\XKV@tempa
  }%
  \expandafter\XKV@s@tkeystwice\expandafter{\XKV@tempb}{#1}%
}
\def\XKV@s@tkeystwice#1#2{%
  \XKV@setheadkeys{#2}%
  % Set the usual xkeyval's head keys:
  \XKV@usepresetkeys{#2}{preseth}%
  \XKV@s@tkeys{#1}{#2}%
  \XKV@s@tkeys{#1}{#2}%
  % Set the usual xkeyval's tail keys:
  \XKV@usepresetkeys{#2}{presett}%
  \let\CurrentOption\@empty
}
% Unlike xkeyval package's \XKV@usepresetkeys, \XKV@setheadkeys instantiates 
% head/ordered keys whether or not they appear in the current (user-supplied) key-value
% list.
\def\XKV@setheadkeys#1{%
  \XKV@presettrue
  \XKV@for@eo\XKV@fams\XKV@tfam{%
    \XKV@makehd\XKV@tfam
    \XKV@ifundefined{XKV@\XKV@header headkeys}{}{%
      \XKV@toks\expandafter\expandafter\expandafter
        {\csname XKV@\XKV@header headkeys\endcsname}%
      \@expandtwoargs\XKV@s@tkeys{\the\XKV@toks}{#1}%
    }%
  }%
  \XKV@presetfalse
}

% Example use:

% We could have used command-keys to define these keys, but never mind:
\define@key{box}{boxwidth}[1cm]{\def\boxwidth{#1}}
\define@key{box}{boxheight}[.5cm]{\def\boxheight{#1}}
\define@key{box}{framecolor}[black]{\def\framecolor{#1}}
\define@key{box}{shadecolor}[white]{\def\shadecolor{#1}}
\define@key{box}{shadowcolor}[gray]{\def\shadowcolor{#1}}
\define@key{box}{framesize}[.4pt]{\def\framesize{#1}}
\define@key{box}{boxsep}[5mm]{\def\boxsep{#1}}
% Note: \shadowsize is a fraction of \boxwidth plus \boxheight. [The ratio is given by 
% the key 'shadowratio'.] Hence 'boxwidth' and 'boxheight' must be set before     
% 'shadowratio'. We want to allow the user to set the keys in any order.
\define@key{box}{shadowratio}[.25]{%
  \def\tempa##1.##2\@nil{##1}%
  \edef\tempa{\expandafter\tempa\the\dimexpr#1pt*100\relax\@nil}%
  \edef\shadowsize{\the\dimexpr(\boxwidth+\boxheight)/\tempa}%
}

% Since the values of 'boxwidth' and 'boxheight' are needed when setting 'shadowratio',
% we preset/order 'boxwidth' and 'boxheight' before 'shadowratio'. The user could then
% set the keys in any order he likes.
\orderofkeys{box}{boxwidth,boxheight,shadowratio,framecolor,shadecolor,
  shadowcolor,framesize,boxsep}

% Let us define a sample method that uses these keys and \setkeystwice:
\usepackage{xcolor}
\newcommand*\somebox[2][]{%
  \setkeystwice{box}{#1}%
  \begingroup
  \fboxrule=\framesize\relax
  \setbox0=\hbox{%
    \fcolorbox{\framecolor}{\shadecolor}{%
      \vbox to \boxheight{\vfil\hbox to\boxwidth{\hfil{#2}\hfil}\vfil}%
    }%
  }%
  \hskip\shadowsize\hskip\boxsep
  \color{\shadowcolor}%
  \rule[-\dp0]{\wd0}{\the\dimexpr\ht0+\dp0\relax}%
  \llap{\raisebox{\shadowsize}{\box0\hskip\shadowsize}}%
  \endgroup
}
\makeatother

\begin{document}
% Now the user may set the keys in any order he wishes.
\somebox[boxwidth=1cm,boxheight=.5cm,shadowratio=.25,framesize=1pt]{box 1}
\somebox[boxwidth=2cm,boxheight=1cm,shadowratio=.1,
  framesize=2pt,framecolor=green,shadowcolor=blue]{box 2}
\end{document}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.