Alright, I took another look at this issue and I do not believe this is a duplicate of:
However I also do not believe that rcollyer's analysis is entirely correct. Please consider this example:
ClearAll[Foo]
Options[Foo] = {Bar -> True};
Foo[a_, b__, OptionsPattern[]] := If[OptionValue[Bar], A, B]
{Foo[x, y, Bar -> True], Foo[x, y, Bar -> False], SetOptions[Foo, Bar -> True];
Foo[x, y, Bar -> True], Foo[x, y, Bar -> False], SetOptions[Foo, Bar -> False];
Foo[x, y, {Bar -> True}], Foo[x, y, {Bar -> False}], SetOptions[Foo, Bar -> True];
Foo[x, y], SetOptions[Foo, Bar -> False];
Foo[x, y]}
{A, B, A, B, A, B, A, B}
Observe that OptionValue[Bar]
resolves correctly to True
or False
in each case. One can use a more verbose RHS definition to show that every a_
and b__
match is correct and that b__
does not include the option as rcollyer stated:
ClearAll[Foo]
Options[Foo] = {Bar -> True};
Foo[a_, b__, OptionsPattern[]] := {{a}, {b}, OptionValue[Bar]}
{Foo[x, y, Bar -> True], Foo[x, y, Bar -> False], SetOptions[Foo, Bar -> True];
Foo[x, y, Bar -> True], Foo[x, y, Bar -> False], SetOptions[Foo, Bar -> False];
Foo[x, y, {Bar -> True}], Foo[x, y, {Bar -> False}], SetOptions[Foo, Bar -> True];
Foo[x, y], SetOptions[Foo, Bar -> False];
Foo[x, y]} // MatrixForm
$\left(
\begin{array}{ccc}
\{x\} & \{y\} & \text{True} \\
\{x\} & \{y\} & \text{False} \\
\{x\} & \{y\} & \text{True} \\
\{x\} & \{y\} & \text{False} \\
\{x\} & \{y\} & \text{True} \\
\{x\} & \{y\} & \text{False} \\
\{x\} & \{y\} & \text{True} \\
\{x\} & \{y\} & \text{False} \\
\end{array}
\right)$
Rather I believe the problem you experienced is due the behavior when a Condition
fails. One can see that more than one possible match is checked in this example:
ClearAll[Foo]
Options[Foo] = {Bar -> True};
Foo[a_, b__, OptionsPattern[]] := Null /; Print[{{a}, {b}, OptionValue[Bar]}]
Foo[x, y, Bar -> True];
Foo[x, y, {Bar -> False}];
{{x},{y},True}
{{x},{y,Bar->True},True}
{{x},{y},False}
{{x},{y,{Bar->False}},True}
Note that each line results in two different alignments being checked: first the correct one, then an incorrect one. Blocking the incorrect one is how rcollyer's method works, but it is not because b__
is "greedy" but rather because the first, correct alignment did not pass the Condition
and another possible alignment is sought. In the second case above the alignment {{x},{y,{Bar->False}},True}
is the source of error. (This may be a semantic dispute but I think it is an important one.)
Although I usually favor separate definitions in this case I think using If
is a more direct solution without unnecessary additional argument testing.