Recall that OptionValue
is a "magic" symbol with nonstandard behavior. The expression OptionValue["bar"]
"by magic" gets its value without it being explicitly passed one, working with its "magic" brother OptionsPattern
in a not-entirely-transparent way. I think it attaches to the first OptionsPattern[]
object which is not used in the final matching with "bar" -> 3
which is not used in the final matching with ."bar" -> 3
I don't yet have a clear idea of what is happening but I can give other examples of weird behavior.
exhibit A
ClearAll[foo]
Options[foo] = {"bar" -> 1};
foo[
first : Except[OptionsPattern[]],
second : OptionsPattern[]
] := {{first}, {second}}
foo["arg", "bar" -> 3]
{{"bar" -> 3}, {}}
"arg"
disappears entirely. Theoretically for the rule onfoo
to apply"arg"
should be attached to eitherfirst
orsecond
patterns, but instead it vanishes as though attached to a third pattern expression"bar" -> 3
is attached tofirst
, implying that it matchesExcept[OptionsPattern[]]
, despite the fact thatMatchQ["bar" -> 3, Except[OptionsPattern[foo]]]
returnsFalse
exhibit B
Let's see what happens if we name the first appearance of OptionsPattern[]
itself.
ClearAll[foo]
Options[foo] = {"bar" -> 1};
foo[
first : Except[op1 : OptionsPattern[]],
second : OptionsPattern[]
] := {{first}, {second}, {op1}}
foo["arg", "bar" -> 3]
{{}, {}, {"bar" -> 3}}
- Once again
"arg"
goes missing, but this time"bar" -> 3
is not attached tofirst
as it was before, leaving bothfirst
andsecond
empty. Instead it is attached (only) toop1
.
a note about Except
Except
at times causes strange behavior. For example, I believe from an earlier question I cannot at the moment find:
Cases[{1, 0, 2, 0, 3}, Except[x : 0] :> x]
{Removed["$Variable"][1], Removed["$Variable"][1], Removed["$Variable"][1]}
Combining this somewhat peculiar pattern construct with the "magic" of OptionsPattern
may simply be a bad idea at this time, unless and until this edge case is specifically addressed by the developers.
version differences
In version 10.1 from your second block of code I get:
In[6]:= foo["xx", "bar" -> 3]
During evaluation of In[6]:= OptionValue::rep: def is not a valid replacement rule. >>
Out[6]= {"xx", "bar" -> 3, 1}
Did I enter it wrong or has behavior changed?