5
$\begingroup$

Given that I have a function func as follow:

To check the value of options, I using the step-by-step method If[]

Options[func] = {Method -> Automatic, WorkingPrecision -> MachinePrecision, Order->2}; func::badval = "`1` is not a valid value of option `2`"; func[arg1_,arg2_, opts : OptionsPattern[]] := Module[{method, prec, order}, method = Method /. {opts} /. Options[func]; prec= WorkingPrecision/. {opts} /. Options[func]; order= Order/. {opts} /. Options[func]; (*Check the value of the options*) If[ ! MemberQ[ {{"Euler", 2}, {"Midpoint", 2}, {"Heun", 2}, {"Heun", 3}, {"Kutta", 3}, {"RK", 4}, {"Gill", 4}, Automatic}, method], Message[func::badval, method, Method]; Return[$Failed]]; If[ ! (prec === MachinePrecision || NumericQ[prec]), Message[func::badval, prec, WorkingPrecision]; Return[$Failed]]; If[ ! (Head[order] ===Integer&& order >= 1), Message[func::badval, order, Order]; Return[$Failed]]; (*main implementation*) arg1 + arg2 ] 

Test

func[1, 2, WorkingPrecision -> MachinePrecisio, Order -> 1., Method -> Automati] 

func::badval: Automati is not a valid value of option Method

However, I hope the warning information should like this or like the Plot(see below)

func::badval: Automati is not a valid value of option Method

func::badval: MachinePrecisiois not a valid value of option WorkingPrecision

func::badval: 1.is not a valid value of option Order

The built-in throw the warning information

Plot[2 Sin[x] + x, {x, 0, 15}, PlotRange -> {a, c}, Filling -> bb, Mesh -> pp, Axes -> Fals, WorkingPrecision -> MachinePrecisi] 

General::prng: Value of option PlotRange -> {a,c} is not All, Full, Automatic, a positive machine number, or an appropriate list of range specifications.

Plot::wprec: Value of option WorkingPrecision -> MachinePrecisi is not a positive machine-sized real or integer. >>

Mesh::ilevels: pp is not a valid mesh specification. >>

Question

  • How to check the value of options like the built-in functions, especially when the function have many options(the option number of Plot is 60)?

As said by Mr.Wizard in the comment, I hope that the func executes the following operation:

(1) Multiple messages are issued

(2) Using default option values.

$\endgroup$
6
  • 3
    $\begingroup$ Just add a module variable fail=False, change the Return[$Failed] to fail=True, after all checks, add If[fail,Return[$Failed]]. $\endgroup$ Commented Jun 28, 2015 at 7:01
  • $\begingroup$ What is your reason for preferring method/.{opts}/.Options[func] over OptionValue[method]? $\endgroup$ Commented Jun 28, 2015 at 7:03
  • $\begingroup$ In your Plot example (1) multiple messages are issued and (2) the plot is still rendered using default option values. Are both these behaviors something you wish to duplicate? $\endgroup$ Commented Jun 28, 2015 at 7:05
  • 5
    $\begingroup$ Okay. That is an old manual, and while it is still an authoritative reference for its time there are newer methods available. This is such a case. OptionValue is now the preferred method in most cases and I intend to use it where applicable. I suggest you read: (355) $\endgroup$ Commented Jun 28, 2015 at 7:16
  • $\begingroup$ I am waiting for you to answer my question about the behaviors you wish to emulate before I start on an answer. Better yet update your question to include a specific description of what you mean by "like the built-in functions." $\endgroup$ Commented Jun 28, 2015 at 7:28

1 Answer 1

5
$\begingroup$

I believe the simplest change to your code is to replace the Return[$Failed] expressions with Sets that restore the default values of the options:

ClearAll[func] Options[func] = {Method -> Automatic, WorkingPrecision -> MachinePrecision, Order -> 2}; func::badval = "`1` is not a valid value of option `2`"; func[arg1_, arg2_, opts : OptionsPattern[]] := Module[{method, prec, order}, method = OptionValue[Method]; prec = OptionValue[WorkingPrecision]; order = OptionValue[Order]; (*Check the value of the options*) If[! MemberQ[{{"Euler", 2}, {"Midpoint", 2}, {"Heun", 2}, {"Heun", 3}, {"Kutta", 3}, {"RK", 4}, {"Gill", 4}, Automatic}, method], Message[func::badval, method, Method]; method = Method /. Options[func]]; If[! (prec === MachinePrecision || NumericQ[prec]), Message[func::badval, prec, WorkingPrecision]; prec = WorkingPrecision /. Options[func]]; If[! (Head[order] === Integer && order >= 1), Message[func::badval, order, Order]; order = Order /. Options[func]]; (*main implementation*){arg1 + arg2, {method, prec, order}}] 

Now:

func[1, 2, WorkingPrecision -> MachinePrecisio, Order -> 1., Method -> Automati] 

func::badval: Automati is not a valid value of option Method

func::badval: MachinePrecisio is not a valid value of option WorkingPrecision

func::badval: 1.` is not a valid value of option Order

General::stop: Further output of func::badval will be suppressed during this calculation. >>

{3, {Automatic, MachinePrecision, 2}} 

(Note that I included the option values explicitly in the output for visibility.)

This does make the assumption that the Options settings are never wrong. A more robust method would be to keep a separate set of known safe option values as hidden defaults, e.g.:

$defaultOptions[func] = {Method -> Automatic, WorkingPrecision -> MachinePrecision, Order -> 2}; 

Then in the function body use:

Method /. $defaultOptions[func] 

This will protect against an invalid SetOptions[func, . . .] usage as well.

$\endgroup$
1
  • $\begingroup$ That's a good way - perhaps add the fact default is restored to msg. +1 $\endgroup$ Commented Jun 28, 2015 at 7:59

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.