Re: Re: Options in self-defined functions
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg1798] Re: [mg1779] Re: [mg1612] Options in self-defined functions
- From: Allan Hayes <hay at haystack.demon.co.uk>
- Date: Mon, 31 Jul 1995 23:07:00 -0400
In [mg1779] Re: [mg1612] Options in self-defined functions "Wm. Martin McClain" <wmm at chem.wayne.edu> wrote > *********************************************************** Here is a further question along the lines of one Allan Hayes answered for Scott A. Hill [mg1612]. I have had trouble making a PACKAGE that contains a function with options. I used the WRI package Miscellaneous`Audio` as a model, but I must have missed some essential detail, because it does not work quite correctly. Here is the full text of a didactic package containing one fairly useless but simple function AnyF, described below in its usage statement: (**************cell begins*************************) BeginPackage["OptionsExample`"]; AnyF::usage = "AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi."; Begin["`Private`"]; Options[AnyF] = {Name->Tan, ScaleFactor->2Pi}; AnyF[x_,opts___](*public*) := iaf[x,opts](*private*); iaf[x_,opts___]:=Module[{fn,sf}, {fn,sf} = {Name,ScaleFactor}/.{opts}/.Options[AnyF]; af[x,fn,sf]]; af[x_,fn_,sf_]:=fn[x*sf]; Protect[AnyF]; End[]; EndPackage[] (****************cell ends************************) Test the package: ?AnyF AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi. AnyF[t] Tan[2 Pi t] The defaults work. Now try it with options: AnyF[w,Name->Log,ScaleFactor->7] Tan[2 Pi w] The options do NOT work! Ask Mma what it thinks the default options are: Options[AnyF] { OptionsExample`Private`Name -> Tan, OptionsExample`Private`ScaleFactor -> 2 Pi} To make them work you have to give the full names: AnyF[w,OptionsExample`Private`Name->Log, OptionsExample`Private`ScaleFactor->7] Log[7 w] It works, but these long names are not what one wants. How do you make the short names work? I have tried several things: (1) Put the Options statement in the outer part, not the Private` part. (2) Make usage statements for Name and ScaleFactor. These just make things worse. Can anybody spot the problem? Thanks in advance- Martin McClain AnyF[t] Tan[2 Pi t] The defaults work. Now try it with options: AnyF[w,Name->Log,ScaleFactor->7] Tan[2 Pi w] The options do NOT work! Ask Mma what it thinks the default options are: Options[AnyF] { OptionsExample`Private`Name -> Tan, OptionsExample`Private`ScaleFactor -> 2 Pi} To make them work you have to give the full names: AnyF[w,OptionsExample`Private`Name->Log, OptionsExample`Private`ScaleFactor->7] Log[7 w] It works, but these long names are not what one wants. How do you make the short names work? I have tried several things: (1) Put the Options statement in the outer part, not the Private` part. (2) Make usage statements for Name and ScaleFactor. These just make things worse. Thanks in advance- Martin McClain >************************************************************** Dear Martin, I hope that the following helps Allan Hayes De Montfort University Leicester hay at haystack.demom.co.uk ************* The fix for your problem is to create Name and ScalingFactor in the package context, "OptionsExample`". This is usually done by a usage message above Begin["`Private`"] . Alternatively, moving the definition of Options[AnyF] above Begin["`Private`"] works -- though you seem to have found otherwise. These remedies are demonstrated in Example 2 and Example 3 respectively -- you could use both. In example 4 I make some suggestions about package style. But first let's have a look at what is going on with the code that you sent: EXAMPLE 1 BeginPackage["OptionsExample`"]; AnyF::usage = "AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi."; Begin["`Private`"]; Options[AnyF] = {Name->Tan, ScaleFactor->2Pi}; AnyF[x_,opts___](*public*) := iaf[x,opts](*private*); iaf[x_,opts___]:=Module[{fn,sf}, {fn,sf} = {Name,ScaleFactor}/.{opts}/.Options[AnyF]; af[x,fn,sf]]; af[x_,fn_,sf_]:=fn[x*sf]; Protect[AnyF]; End[]; EndPackage[] General::spell: Possible spelling error: new symbol name "Name" is similar to existing symbols {NameQ, Names}. The option names are created in the context "OptionsExample`Private`" Options[AnyF] {OptionsExample`Private`Name -> Tan, OptionsExample`Private`ScaleFactor -> 2*Pi} When you evaluate AnyF[w,Name->Log,ScaleFactor->7] the context "OptionsExample`Private`" is not one the context path so the context names created above are not visible and new versions of Name and ScaleFactor are created in context "Global`" (this is not shown in the output). The result is that the two versions of the names are not the same; so your new options have no effect in replacement. We can see this by asking for a trace restricted to occurrences of ReplaceAll[...]: Trace[AnyF[w,Name->Log,ScaleFactor->7],_ReplaceAll] {{{{{OptionsExample`Private`Name, OptionsExample`Private`ScaleFactor} /. {Name -> Log, ScaleFactor -> 7}}, {OptionsExample`Private`Name, OptionsExample`Private`ScaleFactor} /. {OptionsExample`Private`Name -> Tan, OptionsExample`Private`ScaleFactor -> 2 Pi}}}} Notice that your new options (in the first occurrence of ReplaceAll ( that is /.) ) have no effect; leaving the default values to operate. EXAMPLE 2 Firse clean up. CleanSlate[Verbose->False]; BeginPackage["OptionsExample`"]; AnyF::usage = "AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi."; Name::usage = "Name is an option for AnyF"; ScaleFactor::usage = "ScaleFactor is an option for AnyF"; Begin["`Private`"]; Options[AnyF] = {Name->Tan, ScaleFactor->2Pi}; AnyF[x_,opts___](*public*) := iaf[x,opts](*private*); iaf[x_,opts___]:=Module[{fn,sf}, {fn,sf} = {Name,ScaleFactor}/.{opts}/.Options[AnyF]; af[x,fn,sf]]; af[x_,fn_,sf_]:=fn[x*sf]; Protect[AnyF]; End[]; EndPackage[] General::spell: Possible spelling error: new symbol name "Name" is similar to existing symbols {NameQ, Names}. Check: Now the option names are global Options[AnyF] {Name -> Tan, ScaleFactor -> 2 Pi} and the new options work AnyF[w,Name->Log,ScaleFactor->7] Log[7 w] We can see this in action Trace[AnyF[w,Name->Log,ScaleFactor->7],_ReplaceAll] {{{{{Name, ScaleFactor} /. {Name -> Log, ScaleFactor -> 7}}, {Log, 7} /. {Name -> Tan, ScaleFactor -> 2 Pi}}}} EXAMPLE 3 CleanSlate[Verbose -> False]; BeginPackage["OptionsExample`"]; AnyF::usage = "AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi."; Options[AnyF] = {Name->Tan, ScaleFactor->2Pi}; Begin["`Private`"]; AnyF[x_,opts___](*public*) := iaf[x,opts](*private*); iaf[x_,opts___]:=Module[{fn,sf}, {fn,sf} = {Name,ScaleFactor}/.{opts}/.Options[AnyF]; af[x,fn,sf]]; af[x_,fn_,sf_]:=fn[x*sf]; End[]; Protect[AnyF]; EndPackage[]; General::spell: Possible spelling error: new symbol name "Name" is similar to existing symbols {NameQ, Names}. Check: Options[AnyF] {Name -> Tan, ScaleFactor -> 2 Pi} AnyF[w,Name->Log,ScaleFactor->7] Log[7 w] EXAMPLE 4 My prefered form of this package. BeginPackage["OptionsExample`"]; Unprotect["`*"]; (* allows repeated loading -useful in development*) Remove["`*"]; (*or ClearAll["`*] *) (* guarantees a clean start -useful in development*) AnyF::usage = "AnyF[x,Name->f,ScaleFactor->s] returns f[s*x], where the replacements are optional. The defaults are Name->Tan and ScaleFactor->2 Pi."; Name::usage = "Name is an option for AnyF"; ScaleFactor::usage = "ScaleFactor is an option for AnyF"; Options[AnyF] = {Name->Tan, ScaleFactor->2Pi}; (*put here as an extra safeguard that option names are in package context*) Begin["`Private`"]; (* an opportunist simplification of your code - not a general form *) (* Flatten allows for nested lists of options *) AnyF[x_,opts___?OptionQ] := Name[ScaleFactor x]/.Flatten[{opts}]/.Flatten[Options[AnyF]]; End[]; Protect["`*"]; (*autmatically protect all exported symbols*) EndPackage[]; General::spell: Possible spelling error: new symbol name "Name" is similar to existing symbols {NameQ, Names}. Check: Options[AnyF] {Name -> Tan, ScaleFactor -> 2 Pi} AnyF[w] Tan[2 Pi w] AnyF[w,Name->Log,ScaleFactor->7] Log[7 w]