While several answers have stressed different aspects of old vs. new way of using options, I'd like to make a few additional observations. The newer constructs OptionValue
- OptionsPattern
provide more safety than OptionQ
, since OptionValue
inspects a list of global Options to make sure that the passed option is known to the function. The older OptionQ
seems however easier to understand since it is based only on the standard pattern-matching and isn't directly related to any of the global properties. Whether or not you want this extra safety provided by any of these constructs is up to you, but my guess is that most people find it useful, especially for larger projects.
One reason why these type checks are really useful is that often options are passed as parameters by functions in a chain-like manner, filtered, etc., so without such checks some of the pattern-matching errors would be very hard to catch since they would be causing harm "far away" from the place of their origin.
In terms of the core language, the OptionValue
- OptionsPattern
constructs are an addition to the pattern-matcher, and perhaps the most "magical" of all its features. It was not necessary semantically, as long as one is willing to consider options as a special case of rules. Moreover, OptionValue
connects the pattern-matching to Options[symbol]
- a global property. So, if one insists on language purity, rules as in opts___?OptionQ
seem easier to understand - one does not need anything except the standard rule-substitution semantics to understand this:
f[a_, b_, opts___?OptionQ] := Print[someOption/.Flatten[{opts}]/.Options[f]]
(I remind that the OptionQ
predicate was designed specifically to recognize options in the older versions of Mathematica), while this:
f[a_, b_, opts:OptionsPattern[]] := Print[OptionValue[someOption]]
looks quite magical. It becomes a bit clearer when you use Trace
and see that the short form of OptionValue
evaluates to a longer form, but the fact that it automaticaly determines the enclosing function name is still remarkable.
There are a few more consequences of OptionsPattern
being a part of the pattern language. One is the speed improvements discussed by @Sasha. However, speed issues are often over-emphasized (this is not to detract from his observations), and I expect this to be especially true for functions with options, since these tend to be the higher-level functions, which will likely have non-trivial body, where most of the computation time will be spent.
Another rather interesting difference is when one needs to pass options to a function which holds its arguments. Consider a following example:
ClearAll[f, ff, fff, a, b, c, d];
Options[f] = Options[ff] = {a -> 0, c -> 0};
SetAttributes[{f, ff}, HoldAll];
f[x_, y_, opts___?OptionQ] :=
{{"Parameters:", {HoldForm[x], HoldForm[y]}}, {" options: ", {opts}}};
ff[x_, y_, opts : OptionsPattern[]] :=
{{"Parameters:", {HoldForm[x], HoldForm[y]}}, {" options: ", {opts}}};
This is ok:
In[199]:= f[Print["*"],Print["**"],a->b,c->d]
Out[199]= {{Parameters:,{Print[*],Print[**]}},{ options: ,{a->b,c->d}}}
But here our OptionQ
-based function leaks evaluation as a part of pattern-matching process:
In[200]:= f[Print["*"],Print["**"],Print["***"],a->b,c->d]
During evaluation of In[200]:= ***
Out[200]= f[Print[*],Print[**],Print[***],a->b,c->d]
This is not completely trivial. What happens is that the pattern-matcher, to establish a fact of match or non-match, must evaluate the third Print
, as a part of evaluation of OptionQ
, since OptionQ
does not hold arguments. To avoid the evaluation leak, one needs to use Function[opt,OptionQ[Unevaluated[opt]],HoldAll]
in place of OptionQ
. With OptionsPattern
we don't have this problem, since the fact of the match can be established purely syntactically:
In[201]:= ff[Print["*"],Print["**"],a->b,c->d]
Out[201]= {{Parameters:,{Print[*],Print[**]}},{ options: ,{a->b,c->d}}}
In[202]:= ff[Print["*"],Print["**"],Print["***"],a->b,c->d]
Out[202]= ff[Print[*],Print[**],Print[***],a->b,c->d]
So, to summarize: I think choosing one method over another is largely a matter of taste - each one can be used productively, and also each one can be abused. I am more inclined to use the newer way, since it provides more safety, but I do not exclude that there exist some corner cases when it will surprise you - while the older method is semantically easier to understand. This is something similar to C-C++ comparison (if this is an appropriate one): automation and (possibly) safety vs. simplicity and purity. My two cents.
{opt1, opt2, opt3} = OptionValue /@ { ... }
. Also, to add to your summary,OptionsPattern[]
andOptionValue[]
produce cleaner code. – Wireropts
- out of habit, and for those rare cases where I want to pass a whole bunch of options to a supporting function, e.g. in a hypotheticalmySpecialPlot
, you just want to filter the options that are valid forListPlot
or whatever, and pass that to the underlying function. You can't useOptionValue
for that because you don't know in advance which options the user has set. – Fatten