3
$\begingroup$

If I have a function illustrated by this simplified example...

f[a_, b_, c_, OptionsPattern[d -> 0]] := Module[{e},
  e = a + b;
  e += c;
  e += OptionValue[d];
  e]

... and I wish to debug it by breaking at the module and setting inputs, e.g.

f[a_, b_, c_, OptionsPattern[d -> 0]] := Module[{e},

{a, b, c} = {1, 2, 3};

e = a + b;
e += c;
e += OptionValue[d];
e

Can something be set along with {a, b, c} = {1, 2, 3} so that OptionValue[d] will work?

In a realistic situation there may be several OptionValue variables throughout the program which would be cumbersome to change for debugging.

A possible solution is to write the code using the old approach. E.g.

f[a_, b_, c_, options___] := Module[{e, d2},

{a, b, c} = {1, 2, 3}; options = Sequence[d -> 4];

opts = Join[{options}, {d -> 0}];
d2 = d /. opts;
e = a + b;
e += c;
e += d2;
e

Screenshot

enter image description here

$\endgroup$
  • $\begingroup$ I think that It is not possible to set values for a, b, c after you have interrupted execution because they are not variables. They are pattern names. Their values are substituted in immediately when a pattern match is found and a replacement happens. If the were module variables like e then it would be possible to set other values for them. OptionValue and OptionsPattern are special, I don't think it is even possible to implement them using the standard constructs we have available (please do correct me if I am wrong!). I have never looked at what OptionValue does in ... $\endgroup$ – Szabolcs Feb 14 '17 at 10:38
  • $\begingroup$ ... a dialog that was entered when interrupting this function inside of the Module. $\endgroup$ – Szabolcs Feb 14 '17 at 10:39
  • $\begingroup$ I tried to break inside of the module using an Assert[False] (as I usually do), and the stack window shows a "local" OptionsPatternVariable that looks just like a Module variable. But setting it manually does not always have an effect. on the final output of the function. $\endgroup$ – Szabolcs Feb 14 '17 at 10:45
  • $\begingroup$ Seeing your edit I do not understand the question. I can't think of a scenario where a=1 would work in a dialog. How specifically are you setting it? If you just want to give the options pattern a name, you can always do so f[opt : OptionsPattern[]]. No need to resort to the old version. $\endgroup$ – Szabolcs Feb 14 '17 at 10:52
  • 2
    $\begingroup$ Slightly related: Changing options inside a function. If it's just for debugging, maybe you could Unprotect@OptionValue and simply assign to it: OptionValue[d] = 0? $\endgroup$ – jkuczm Feb 14 '17 at 12:15
2
$\begingroup$

Usually unprotecting and changing definitions of built-in symbols is a bad idea, but for code intended to be used only for debugging, it might be acceptable. So you could unprotect OptionValue and assign downvalues to it:

Unprotect@OptionValue;

{a, b, c, OptionValue[d]} = {1, 2, 3, 4};

e = a + b;
e += c;
e += OptionValue[d];
e
(* 10 *)

Alternatively if you want to make sure that all pattern variables and all calls to OptionValue behave like they do when evaluated inside function body, you could use special environment:

functionCallEnvironment = Function[patt, Function[call, Function[body,
    Replace[Unevaluated@call, Identity[RuleDelayed][Unevaluated@patt, body]],
HoldFirst], HoldFirst], HoldFirst];

Create environment generator for specific pattern of f function:

fEnvGenerator = functionCallEnvironment@f[a_, b_, c_, OptionsPattern[d -> 0]];

Create environment for specific values:

env = fEnvGenerator@f[1, 2, 3, d -> 4];

Evaluate some code in this specific environment:

env[
    e = a + b;
    e += c;
    e += OptionValue[d];
    e
]
(* 10 *)

To see that relevant values are inserted in right places we can evaluate held code:

env@Hold[
    e = a + b;
    e += c;
    e += OptionValue[d];
    e
]
(* Hold[e = 1 + 2; e += 3; e += OptionValue[d -> 0, {d -> 4}, d]; e] *)

Environment works for every possible way of calling OptionValue:

env = functionCallEnvironment[g@OptionsPattern@{d1 -> 1, d2 -> 2}]@g[d1 -> 3];

env@{
    OptionValue@d1,
    OptionValue@d2,
    OptionValue@{d1, d2},
    OptionValue[Automatic, Automatic, d1, Hold],
    OptionValue[{d1 -> 5, d2 -> 6}, d1 -> 7, {d1, d2}]
}
(* {3, 2, {3, 2}, Hold[3], {7, 6}} *)
$\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.