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.
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 on foo to apply "arg" should be attached to either first or second patterns, but instead it vanishes as though attached to a third pattern expression
"bar" -> 3 is attached to first, implying that it matches Except[OptionsPattern[]], despite the fact that MatchQ["bar" -> 3, Except[OptionsPattern[foo]]] returns False
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 to first as it was before, leaving both first and second empty. Instead it is attached (only) to op1.
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?
foo["xx", MaxRecursion -> 3], with non-foooption? (I expected an error but didn't get one.) The problem seems to be thatpattis not passed toOptionValue, so another workaround is to use the full formOptionValue[foo, patt, "bar"]. Perhaps it's confused by the two occurrences ofOptionsPattern[]? – Michael E2 Aug 03 '17 at 12:41Except[_?OptionQ]which seems to be reasonably solid and less-restrictive thanExcept[_Rule]– b3m2a1 Aug 03 '17 at 14:49Shortestbeing superior, which I learned about later. – Mr.Wizard Aug 03 '17 at 16:22