15
$\begingroup$

I'm calling a function f from within a function g and would like to pass any valid options for f to g, replacing some (say, optA and optB) with defaults different from those defined for f.

What is the right way to do this?

I can get things to (seemingly) work with

Options[g] = Join[FilterRules[Options[f], Except[optA | optB]], {optA -> 0, optB -> 0}];
g[x, opts : OptionsPattern[]] := 
    f[x, opts, OptA -> OptionValue[OptA], optB -> OptionValue[optB]]

bit this looks pretty verbose to me. Is there a better, more idiomatic, way?

$\endgroup$
  • 1
    $\begingroup$ This is how I usually do it except for the minor difference of writing it as Options[g] = Options[f]; SetOptions[g, {optA -> 0, optB -> 0}] (instead of filtering). The most annoying thing for me about this solution is that if I later SetOptions on f, the change won't be inherited by g. But this is what happens with builtins too (e.g. Plot vs Graphics) and the workaround is rather verbose and complicated. $\endgroup$ – Szabolcs Nov 12 '14 at 19:37
  • $\begingroup$ @Szabolcs: So the explicit OptA -> OptionValue[OptA], optB -> OptionValue[optB] in the call to f is indeed necessary? $\endgroup$ – orome Nov 12 '14 at 20:06
14
$\begingroup$

Here is what I do in such cases:

ClearAll[g, f];
Options[f] = {optA -> 1, optB -> 1, optC -> 1};
f[x_, opts : OptionsPattern[]] := 
   {OptionValue[optA], OptionValue[optB], OptionValue[optC]}

Options[g] = {optA -> 0, optB -> 0};
g[x_, opts : OptionsPattern[{g, f}]] := f[x, opts, Sequence @@ Options[g]]

In other words, only define options for g which belong to g, and inherit other options from f via the argument of OptionsPattern. Also, pass all options of g explicitly in the call to f, as in Sequence @@ Options[g]. The fact that they come after opts means that they will be over-ridden by opts, as they should be.

Examples:

g[1]

(* {0, 0, 1} *)

g[1, optA -> 2]

(* {2, 0, 1} *)

The added advantage of this scheme is that it is free from the flaw mentioned by Szabolcs, in that subsequent changes of Options[f] will be picked up in this method automatically.

$\endgroup$
  • $\begingroup$ This is a great solution, but I can't get it to work for me in practice. I get errors deep in my code about some options not being valid. I'll see if I can generate an M(N)WE. $\endgroup$ – orome Nov 13 '14 at 18:37
2
$\begingroup$

Trick that I sometimes find useful is "inheriting" of default option value from another symbol using delayed rule like:

optName :> OptionValue[anotherSymbol, optName]

With f defined as:

ClearAll[f];
Options[f] = {optA -> 1, optB -> 1, optC -> 1};
f[x_, opts : OptionsPattern[]] := OptionValue[{optA, optB, optC}]

We can define g in following way:

ClearAll[g];
(* Inherit all options from f *)
Options[g] = # :> OptionValue[f, #] & @@@ Options[f];
(* Change default values of some of them. *)
SetOptions[g, optA -> 0, optB -> 0];
g[x_, opts : OptionsPattern[]] := f[x, opts, Options[g]]

Basically it works as previous solutions

g[x]
(* {0, 0, 1} *)
g[x, optA -> 2, optC -> 2]
(* {2, 0, 2} *)

g inherits options from f in all situations, not only in above specific function call.

OptionValue[g, {optA, optB, optC}]
(* {0, 0, 1} *)

If you change default options of f, then non-overridden default options of g will inherit this change in all circumstances:

SetOptions[f, optC -> 2];
g[x]
(* {0, 0, 2} *)
OptionValue[g, {optA, optB, optC}]
(* {0, 0, 2} *)

Also at any time you can decide to change default value of any option (not only those overridden when g was defined) only on g without affecting f.

SetOptions[g, optC -> 0];
g[x]
(* {0, 0, 0} *)
f[x]
(* {1, 1, 2} *)

You can also, at any time, decide to use inherited option value:

SetOptions[g, optA :> OptionValue[f, optA]];
g[x]
(* {1, 0, 0} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.