15

I have a function that looks like:

(a : pump[_, __])["curve QH", opts : OptionsPattern[]] :=
  Plot[x, {x, 0, 2}, Frame -> True, FrameLabel -> {"a", "b"}, 
  Evaluate[FilterRules[{opts}, Options[Plot]]]

This code allows me to substitute the option of Plot, with whatever I may want (where pump acts like a very simple object).

Now suppose I want to use an option to define if a Plot or a Table should be outputed.

I imagined something like this:

(a : pump[_, __])["curve QH", opts : OptionsPattern["type" -> "plot"]] :=
 Which[
  OptionValue["type"] == "plot",
  Plot[x, {x, 0, 2}, Frame -> True, FrameLabel -> {"a", "b"}, 
   Evaluate[FilterRules[{opts}, Options[Plot]]]],
  OptionValue["type"] == "table",
  Table[x, {x, 0, 2, 0.1}]
  ]

but it doesn't work.

What is the best strategy to use Options with this kind of definition?

P. Fonseca
  • 6,665
  • 2
  • 28
  • 60

1 Answers1

17

There are two problems I see with this code. The first one, and the one which gives you immediate problem you reported, is that, as it looks, short (magical) form of OptionValue does not work with SubValues - based definitions. So, you should replace

OptionValue["type"]

with

OptionValue[{opts}, "type"]

Or, if you wish to associate the option with pump directly and use it within the SubValue, you need to use

OptionValue[pump, {opts}, "type"]

instead.

The second, "conceptual" problem, is that you are really trying to use options for function dispatch, but in doing this your way, you give up the powerful rule-based function dispatch mechanism that is naturally available in mma. This is what I would do instead:

ClearAll[pump, dispatch];
(a : pump[_, __])["curve QH", opts : OptionsPattern["type" -> "plot"]] :=
    dispatch[pump, OptionValue[{opts}, "type"]][a, "curve QH", opts];

dispatch[pump, "plot"][_, _, opts : OptionsPattern[]] :=
   Plot[x, {x, 0, 2}, Frame -> True, FrameLabel -> {"a", "b"}, 
      Evaluate[FilterRules[{opts}, Options[Plot]]]];

dispatch[pump, "table"][_, _, opts : OptionsPattern[]] :=
   Table[x, {x, 0, 2, 0.1}]

I delegated the dispatch to a new (extra) symbol dispatch, introduced specifically for this purpose. This looks cleaner and more extensible to me than using Which statement.

EDIT

Addressing the issue raised in comments: note that, as another manifestation of OptionValue - OptionsPattern magic being lost for SubValues- based functions, the above solution, as written, will not provide the intended default behavior, when the "type" option is not explicitly given. To make that work, one can do:

(a : pump[_, __])["curve QH", opts : OptionsPattern["type" -> "plot"]] :=
    dispatch[
       pump, 
       OptionValue[{opts,"type" -> "plot"}, "type"]
    ][a, "curve QH", opts];

adding the default option explicitly in OptionValue.

rcollyer
  • 33,976
  • 7
  • 92
  • 191
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • Everything works fine, with the exception that "type" default value ("plot") isn't being considered. If I set no option, it ends up calling dispatch[pump, "type"] (which isn't defined) – P. Fonseca Apr 30 '12 at 13:44
  • @P.Fonseca It looks like this is another manifestation of OptionValue - OptionsPattern having lost some of their magic properties for SubValues. Just change OptionValue[{opts}, "type"] to OptionValue[{opts,"type" -> "plot"}, "type"] and it should work. – Leonid Shifrin Apr 30 '12 at 15:12
  • Your last suggestion works. Thank you. When you can, please update your answer so that both "solutions" are shown: the one that should work if the magic was fully integrated (and that will, one day, eventually work...), and the one with your work around from your comment. Than you again... – P. Fonseca Apr 30 '12 at 19:17
  • @P.Fonseca Done. – Leonid Shifrin Apr 30 '12 at 19:26
  • 1
    If you wish to associate the set of options with pump, and access them via its SubValues, then you need to use OptionValue[pump, {opts}, optName], instead. – rcollyer May 09 '12 at 20:11
  • @rcollyer That's a good point. Care to edit my answer and include it, or do you want me to do this? – Leonid Shifrin May 09 '12 at 20:16
  • Added it. Check it for grammar, wording, etc., if you would. – rcollyer May 10 '12 at 14:10
  • @rcollyer Thanks, perfect! Besides, me checking your edit for grammar and wording does not make much sense, I am not even a native speaker (and the number of typos and other language blunders I notice in my comments and posts upon reading them a while after they were posted is just ridiculous - and I can imagine how many more I just never notice ) :) – Leonid Shifrin May 10 '12 at 14:29
  • The irony of my comment did not elude me. But, I find having another person check it is helpful. – rcollyer May 10 '12 at 14:43