5

The implementation of the built-in OptionValue contains some piece of magic so that

OptionValue[name] is equivalent to OptionValue[f, name], where f is the head of the left-hand side of the transformation rule in which OptionValue[name] appears.

Does anybody have an idea for how to achieve something similar for Options, i.e. implement an autoOptions[] that would resolve to the options defined for the symbol on the left hand side of the transformation rule in which autoOptions[] appears? For clarity, what I am looking for is a way to make

Options[foo]={bar->1};
foo[OptionsPattern[]]:=autoOptions[]
foo[]

output {bar->1}

The eventual goal is to do something like requested in this question without having to change anything but the RHS of a definition.

Community
  • 1
  • 1
Janus
  • 5,421
  • 2
  • 26
  • 37
  • Please give a pseudocode example of what you expect. – Mr.Wizard Mar 17 '11 at 07:29
  • 1
    Maybe I'm missing something, but why can't you just use `Options[symbol]` on the RHS? – Michael Pilat Mar 17 '11 at 07:34
  • @Michael: sure, I can and I do -- this is more of a curiosity thing :) Plus I have seen a few funky bugs from copying code around and forgeting to change symbols in constructs of this type. – Janus Mar 17 '11 at 07:43

1 Answers1

6

Here is a simple, very schematic version:

Module[{tried},
  Unprotect[SetDelayed];    
  SetDelayed[f_[args___, optpt : OptionsPattern[]], rhs_] /; 
    !FreeQ[Unevaluated[rhs], autoOptions[]] :=
     Block[{tried = True},
       f[args, optpt] :=  
         Block[{autoOptions}, autoOptions[] = Options[f]; rhs]] /; ! TrueQ[tried];
  Protect[SetDelayed];]

Your usage:

In[8]:= Options[foo] = {bar -> 1};
foo[OptionsPattern[]] := autoOptions[]
foo[]

Out[10]= {bar -> 1}

Note that this won't work when explicit options are also passed - accounting for them is some more work, and this is not generally a good practice since I overloaded SetDelayed - but you asked for it and you get it.

Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • Thanks Leonid. Fiddling with SetDelayed was the only way I could think of as well (although your implementation is much nicer than what I had in mind), and I agree that it wouldn't qualify as good practice. Still, the pattern is specific enough that I might consider it... – Janus Mar 18 '11 at 01:12
  • @Janus I actually used similar patterns with `SetDelayed` a few times and personally am not fanatically against this. What really matters IMO is that such things are completely localized to only your uses and isolated. If it is your own code, you always have a freedom to define custom assignment operators rather than changing `SetDelayed`. The latter is usually needed when you want to make some run-time modifications or inspections of definitions made in some other code (say, packages being loaded), to which you don't have direct access or which you don't want to access or modify directly. – Leonid Shifrin Mar 18 '11 at 01:51
  • @Leonid. Yes, I agree. Maybe a custom `SetDelayed` in infix notation, say `~def~` could work without being too ugly. This would even simplify your implementation further by alleviating the need for the `tried` trick. Still, I can't help but wonder if `OptionValue` is really handled by `SetDelayed`. – Janus Mar 18 '11 at 04:03
  • @Janus There is some magic involved in `OptionsPattern - OptionValue`, no question about it. While these are handy, I have mixed feelings about them. The older `OptionQ` predicate was only using the standard language constructs (rules), and could be understood easily - it was enough to know how parameters are passed and how patterns work to know exactly how options work. Not so with `OptionValue` and `OptionsPattern`. I would prefer them to be more transparent, implemented in the top level mma. – Leonid Shifrin Mar 18 '11 at 10:38
  • @Janus But since modifying `SetDelayed` seems the only clear way to do it, I understand that it is safer to get this wired in on the system level, since `SetDelayed` is too important and fundamental to mess with it explicitly. Whether or not it was done by actually modifying the built-in rules (code) for `SetDelayed` is a pretty good question, I'd like to know the answer too. – Leonid Shifrin Mar 18 '11 at 10:40
  • @Leonid. Seems we share the feeling that implementing `OptionValue` by modifying `SetDelayed` would count as cheating :) -- guess this is what lead me to post this question. – Janus Mar 21 '11 at 01:06