MathGroup Archive 2004

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

Search the Archive

Re: Package dependencies

This is a very ingenious hack indeed; it's worth commenting line by line. Let's
replace the package c.m with c2.m:


f := (

How does c2.m work?
BeginPackage["a`"]: makes sure that f is placed in the correct context and adds
this context to $ContextPath (basically duplicating the work of a.m); otherwise
we wouldn't be able to access a`f simply as f;

Clear[f]: without it we'd get infinite recursion when f on the right-hand side
is evaluated;

Get["a`"]: not Needs["a`"] because BeginPackage["a`"] modifies $Packages, so
Needs would decide that a.m was already loaded. For the same reason Get["a`"]
cannot be omitted, since BeginPackage["b`","a`"] in b.m also uses Needs!

But a hack is still a hack and it is easy to build a 'counter-example' when it
won't work. The stub definition for f in c2.m will be used when f is evaluated,
while the phrase "when f is first used" means something like "when symbol f is
first encountered by the parser". So if we have a definition

f /: Hold[f[1]]=1

in b.m then evaluating Hold[f[1]] will not load b.m, and therefore c2.m does
not accurately emulate the behaviour of DeclarePackage:





Not to mention several smaller nuisances: if b.m depends on several base
packages then you'll have to manually find the one in which f is defined; if
several packages depend on a.m then Get["a`"] will load a.m several times.

Maxim Rytin
m.r at

Omega Consulting wrote:

> On a modern computer, package loading is quick. Unless the package is very
> large (or part of a large set of interdependent packages), DeclarePackage
> is not really necessary. Just use Get or Needs in c.m.
> However, if you must load the packages when f is first used, you can create
> a "stub" function. Something like:
> BeginPackage["a`"]
> f := (
>    Clear[f];
>    Get["a`"];
>    Needs["b`"];
>    f
> )
> EndPackage[]
> In[1]:= << c`
> In[2]:=
> ?f
> a`f
> f := (Clear[f]; << a`; Needs[b`]; f)
> So f is defined to load a` and b`, which re-defines f.
> In[3]:= f[1]
> Out[3]= 1
> In[4]:=
> ?f
> a`f
> f[0] = 0
> f[1] = 1
> At 04:07 AM 1/20/2004, Maxim wrote:
> >Suppose we have a package a.m defining function f:
> >
> >BeginPackage["a`"]
> >f[0] = 0
> >EndPackage[]
> >
> >Then we create package b.m which introduces additional definitions for
> >f:
> >
> >BeginPackage["b`","a`"]
> >f[1] = f[0] + 1
> >EndPackage[]
> >
> >Now after loading b.m we'll have f[0]=0 and f[1]=1. Finally, we want to
> >create a package c.m that determines when b.m should be autoloaded. We
> >add the following line to c.m:
> >
> >DeclarePackage["b`","f"]
> >
> >Unfortunately, it doesn't work that way:
> >
> >In[1]:=
> ><<c`
> >f[1]
> >
> >Out[2]=
> >1+f[0]
> >
> >(standalone kernel will also give f::shdw warning). The reason is that
> >DeclarePackage creates symbol f (with attribute Stub) in the b` context.
> >This implementation decision seems rather questionable: the idea of
> >DeclarePackage is to load b.m when f is first used, which is exactly
> >what we want here -- but nobody said the symbol f was needed in context
> >b`!
> >
> >Probably this difficulty can be avoided by some creative usage of Remove
> >and $NewSymbol, but simply adding Remove["b`f"] to b.m won't solve the
> >problem completely.
> >
> >This is exactly the situation with Geometry\Polytopes.m,
> >Graphics\Polyhedra.m and Graphics\Kernel\init.m -- you can use
> ><<graphics` to declare most of the symbols in all the Graphics\*
> >packages, but not Tetrahedron, Cube and others because there are
> >definitions for them both in Polytopes.m and Polyhedra.m.
> >
> >Maxim Rytin
> >m.r at
> --------------------------------------------------------------
> Omega Consulting
> "The final answer to your Mathematica needs"

  • Prev by Date: Re: typesetting fractions
  • Next by Date: brackets and parenthesis
  • Previous by thread: Re: Package dependencies
  • Next by thread: Tail recursion and local functions