3

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?

Sylvain Leroux
  • 1,509
  • 5
  • 15

1 Answers1

2

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.

Sylvain Leroux
  • 1,509
  • 5
  • 15