MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

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]



  • Prev by Date: Re: Re: Problems with NIntegrate
  • Next by Date: Re: Exponetial Fit
  • Previous by thread: Re: Re: Problems with NIntegrate
  • Next by thread: Re: Re: Options in self-defined functions