# How to replace an option value in a rules list captured by OptionsPattern?

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?

• "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. Mar 24 '20 at 15:58
• 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 ;) Mar 24 '20 at 16:12
• So, something like the result of DeleteDuplicatesBy[Join[{a -> 1, b -> 2}, {a -> 3}], First]? Mar 24 '20 at 16:17
• Maybe @J.M.. Right now, I was looking at FilterRules. It accepts the FilterRules[..., Except[...]] syntax that seems promising. Mar 24 '20 at 16:36
• What about FilterRules[{opts}, Except["a"]] // Append[a->3]? Mar 24 '20 at 16:44

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.