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]