3
$\begingroup$

While experimenting with options, I tried to replace a value in the rules list captured by OptionsPattern. However, the following approach does not work as I expected:

f[opts:OptionsPattern[]]:= Hold[opts, a->3]
Column[{
    f[],
    f[a->1],
    f[a->1,b->2]
}]
Hold[a->3]
Hold[a->1,a->3]
Hold[a->1,b->2,a->3]

I would have expected the value for the a option to be replaced. But instead, a new rule is added to the sequence.
So, is there a way to replace a rule in the option sequence?

$\endgroup$
5
  • 1
    $\begingroup$ "I would have expected the value for the a option to be replaced. But instead, a new rule is added to the sequence." - usually this is fine, since options are parsed left to right, and leftmost ones have higher priority. See e.g. this older question. $\endgroup$
    – J. M.'s torpor
    Mar 24 '20 at 15:58
  • $\begingroup$ Yes, I already noticed that behavior when writing a thin wrapper around the Plot function. This question is mostly of theoretical concern while I'm studying more in-depth the Wolfram Language. So, let's pretend I really really want to replace (or delete BTW) a value in the options list ;) $\endgroup$ Mar 24 '20 at 16:12
  • $\begingroup$ So, something like the result of DeleteDuplicatesBy[Join[{a -> 1, b -> 2}, {a -> 3}], First]? $\endgroup$
    – J. M.'s torpor
    Mar 24 '20 at 16:17
  • $\begingroup$ Maybe @J.M.. Right now, I was looking at FilterRules. It accepts the FilterRules[..., Except[...]] syntax that seems promising. $\endgroup$ Mar 24 '20 at 16:36
  • $\begingroup$ What about FilterRules[{opts}, Except["a"]] // Append[a->3]? $\endgroup$ Mar 24 '20 at 16:44
2
$\begingroup$

As noticed by J.M. in a comment, it is usually not necessary to replace an option since " options are parsed left to right, and leftmost ones have higher priority" More details in this older question.


Filtering rules

But let's pretend here I really really want to replace a rule in the options list. A possible solution in two steps would be:

  1. Using FilterRules with the FilterRules[..., Except[...]] syntax we will first delete the rule we want to replace;
  2. Using the classic list manipulation functions (like Append) we will then add a new rule with the expected value.
f[opts:OptionsPattern[]] := FilterRules[{opts}, Except["a"]] // Append[a->3]
Column[{
    f[],
    f[a->1],
    f[b->2],
    f[a->1, b->2]
}]

Producing:

{a->3}
{a->3}
{b->2,a->3}
{b->2,a->3}

Converting to an association

An alternate solution is to convert first the rules list to an association. In the process, duplicate rules replace their predecessor. Finally, using Normal we can convert back from an association to a list:

f[opts:OptionsPattern[]] := Normal[Association[opts, a->3]]
Column[{
    f[],
    f[a->1],
    f[b->2],
    f[a->1, b->2]
}]

Producing almost the same result as above:

{a->3}
{a->3}
{b->2,a->3}
{a->3,b->2}

As you can see, in the last test, the a value appears first--something that has some consistency with the notion or replacement, even if I'm not sure this behavior is guaranteed.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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