April 2002 Draft
JavaScript 2.0
Core Language
Packages
|
Monday, March 4, 2002
Packages are an abstraction mechanism for grouping and distributing related code. Packages are designed to be linked at run time to allow a program to take advantage of packages written elsewhere or provided by the embedding environment. JavaScript 2.0 offers a number of facilities to make packages robust for dynamic linking:
A package is defined using the following syntax:
When a package is defined, it may, but is not required to, be given a PackageName, which is a series of dot-separated identifiers. It is implementation-defined what the restrictions, if any, are on naming packages to avoid clashes with other packages that may be present.
The Block contains the body of a package P. The Block
is evaluated at the time package P is loaded. Any public
top-level definitions are available to other
packages that import
package P. Any public
class and interface
member definitions are available to all other packages, regardless of whether they import
package P.
Top-level and class and interface definitions defined by P in another namespace N
are available to other packages only if they use
namespace
N or qualify the access with
namespace N.
A package is loaded (its body is evaluated) when the package is first imported or invoked directly (if, for example, the
package is on an HTML web page). Some standard packages are loaded when the JavaScript engine first starts up. When a package
is loaded, its statements are evaluated in order, which may cause other packages to be loaded along the way when import
directives are encountered. Circularities are not allowed in the graph of package imports.
Two attempts to load the same package in the same environment result in sharing of that package. What constitutes an environment is necessarily application-dependent. However, if package P1 loads packages P2 and P3, both of which load package P4, then P4 is loaded only once and thereafter its code and data is shared by P2 and P3.
Javascript does not support package definition circularities (two packages A and B that each import the other), although an implementation may provide such a facility as an extension.
A package P can reference another package Q via an import
directive:
An import
directive may be preceded by attributes; however, all such
attributes must evaluate to either true
or false
.
There are two ways an import
directive can name a package to be imported:
import
directive may use a PackageName. In this case,
the system looks for a package with that exact PackageName on its implementation-defined
search path.import
directive may use a literal string. In this case, the system interprets the contents of the
string in an implementation-defined manner in order to locate the package. Specific JavaScript 2.0 embeddings should define
the manner in which the contents of the string are interpreted. For example, a browser embedding may be defined to interpret
the string as a URI and look for a package at the location given by that URI.If provided, ParenListExpression should be a list
of namespaces provided by the package. These namespaces are use
d by the import
statement. In order
to resolve name conflicts between packages, IncludesExcludes provides
finer-grain control over which names are imported. include
or exclude
clauses specify which sets
of names are shared as top-level variables. If include
is used, only the listed names are made accessible; if
exclude
is used, all names except the listed ones are made accessible. For example:
package My.P1 {
explicit namespace N;
N const a = "global a";
N const b = "global b";
N class C {
static var x = 2;
}
N const c = new C(i:5); //
Initializes c.i
to 5
const x = "global x";
}
package My.P2 {
import P = My.P1, namespace(N), exclude(N::b, x); //
Imports My.P1
and use
s namespace N
, excluding N::b
and x
c; //
OK; evaluates to the instance of class C
N; //
Error: N
not found because it’s explicit
P.N; //
OK; evaluates to namespace N
in package My.P1
a; //
OK; evaluates to "global a"
b; //
Error: N::b
not found
because it’s excluded
P.b; //
OK; evaluates to "global b"
(P.N)::b; //
Error: N::b
not found
because it’s excluded
x; //
Error:
the global x
not found because it’s excluded
C.x; //
OK; evaluates to 2
}
If no include
or exclude
clause is listed, the effect is the same as if exclude()
were listed.
An import
directive does the following:
const
-bind it to
P in the current scope.explicit
top-level definition N::
n (n in namespace
N) in P, if N::
n is excluded by the given IncludesExcludes,
then skip that definition; otherwise, bind an alias N::
n to P’s N::
n
in the global scope..
. Each such
expression E should evaluate to a namespace S. Evaluate use namespace(
S)
using the given IncludesExcludes.If package P has a public
top-level definition n and package Q imports P
using import PkgP =
P, then package Q can refer to n as either
n or PkgP.
n. The shorter form n is not available if it conflicts with some other
n. To avoid polluting its top-level scope, package Q can import package P using either import PkgP =
P, include()
or import PkgP =
P, exclude(
n)
, in which
case package Q can refer to n only as PkgP.
n.
If package P has an explicit
top-level definition n and package Q imports
P, then package Q can refer to n only as PkgP.
n.
If package P has a top-level definition n in namespace N and package Q imports
P using import PkgP =
P, then package Q can refer to n
as either PkgP.
N::
n or N::
n (in either
of these the name N has to be accessible as well, which may require qualifying it if the accessibility of N
is not public
or using (PkgP.
N)
instead of N if the accessibility
of N is explicit
). Package Q can instead import P using import PkgP =
P, namespace(
N)
to be able to refer to n as plain n, barring name collisions. Alternatively, package Q can
execute import PkgP =
P followed by use namespace(
N)
(or use namespace(PkgP.
N)
) to achieve the same effect.
Waldemar Horwat Last modified Monday, March 4, 2002 |