Skip to main content
replaced http://mathematica.stackexchange.com/ with https://mathematica.stackexchange.com/
Source Link
Source Link
Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k

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.