| April 2002 Draft JavaScript 2.0 Core Language Definitions |    | 
Friday, April 12, 2002
Definitions are directives that introduce new constants, variables, functions, classes, interfaces, namespaces, and packages. All definitions except those of packages can be preceded by zero or more attributes. There must not be any line breaks between the attributes or after the last attribute.
An attribute is an expression (usually just an identifier) that modifies a definition’s meaning. Attributes can specify
a definition’s scope, namespace, semantics, and other hints. A JavaScript program may also define and subsequently use its
own attributes. Attributes can be qualified identifiers (as long as
they don’t start with a () and dotted and function call expressions, but they must be compile-time
constants.
The table below summarizes the predefined attributes.
| Category | Attributes | Behavior | 
|---|---|---|
| Scope | extend(C) | The definition extends class C. | 
| unit | Shorthand for extend(Unit). | |
| Namespace | privateinternalpublic | Makes the definition visible only in the enclosing class’s private namespace ( private),
      the enclosing package’s private namespace (internal), or anywhere (public). | 
| Visibility Modifier | enumerable | This definition can be accessed using the []operator and seen using afor-instatement. | 
| explicit | This top-level definition is not shared via an importdirective. | |
| Evaluation Modifier | compile | This definition defines a compile-time constant. | 
| Class Modifier | final | This class cannot be subclassed. Can be used only on classes. | 
| dynamic | Instances of this class can contain dynamic properties. Can be used only on classes. | |
| Member Modifier | staticconstructoroperatorabstractvirtualfinal | The definition creates a global member ( static), constructor (constructor), operator
      override (operator), or instance member (abstract,virtual, orfinal)
      of the enclosing class or interface. If defining an instance member, the definition must (abstract),
      can (virtual), or cannot (final) be overridden in subclasses. Can be used only on class
      or interface members. | 
| overrideoverride(true)override(false)override(undefined) | Assertion that the definition overrides ( overrideoroverride(true)), may override
      (override(undefined)), or does not override (override(false)) a member of a superclass. Can
      be used only on class or interface members. Controls errors only. | |
| Conditional | truefalse | The definition or directive is ( true) or is not (false) processed. | 
| Memory Management | weak | Makes the defined variable be a weak reference. Can be used only on vardefinitions. | 
| Miscellaneous | prototype | Allows a function to access thisand be used as a prototype-based constructor. If the function
      is an instance member of a class, then the function is visible via the class’sprototypeglobal member
      and can take any object in thethisparameter. | 
| unused | Assertion that the definition is not used. | 
Multiple conflicting attributes cannot be used in the same definition, nor can an identical attribute be repeated. Thus,
virtual final private and public public are both errors.
A scope attribute describes the scope to which a definition applies. If no scope attribute is given, the definition applies to the innermost enclosing scope except when it is hoisted. If that scope is a class or interface, the definition appears as a member of that class or interface. If that scope is a package, the definition appears as a member of that package.
For compatibility with JavaScript 1.5, in some cases a definition’s scope is hoisted to the innermost regional scope R instead of the innermost scope S. This happens only when all of the conditions below are met:
var definition.true.When a definition of n is hosted, the effect is as though n were declared (but not initialized) at the top of the regional scope R.
Definitions not meeting the above criteria are not hoisted. However, an inner non-hoisted definition of name n in scope S within regional scope R prevents n from being referenced or defined in any scope within R but outside S; see definition conflicts.
The extend attribute takes a parameter C, which should be a compile-time constant expression that
evaluates to a class, and adds the definition as a new member of class C. This allows one to add a method to an
existing class C even if C is in an already defined package P. There are several restrictions:
extend attribute can only be used on function, const, class,
    interface, or namespace definitions, or on static var definitions.
    Thus, a class extension cannot add new instance variables to objects of class C; it can, however, add getters
    and setters.static or final, and it cannot override any existing member.
    If the new member is a function, the default is final.explicit namespace. In particular, it means that the new member cannot be public, because
    the public namespace is predefined by the system and not by any package. The default namespace is internal,
    which makes the new member of C visible only from inside the current package.private members, and it cannot see P’s internal members
    if P is not the current package. On the other hand, it can see the current package’s internal
    members.The following example indicates adding methods to the system class String, using a newly created namespace StringExtension:
namespace StringExtension;
StringExtension extend(String) function scramble():String {...}
StringExtension extend(String) function unscramble():String {...}
use namespace(StringExtension);
var x:String = "abc".scramble();
Once the class extension is evaluated, methods scramble and unscramble become available on all
strings in code within the scope of a use namespace(StringExtension). There is no possibility of name clashes
with extensions of class String in other, unrelated packages because the names scramble and unscramble
only acquire their special meanings when qualified by the namespace StringExtension.
Unless one desires to export a class extension to other packages, the default namespace internal generally
works best and simplifies the above example to:
extend(String) {
  function scramble():String {...}
  function unscramble():String {...}
}
var x:String = "abc".scramble();
The unit attribute is defined as though
compile const unit = extend(Unit);
were evaluated at the top level. Unit is the class that holds the definitions of unit
names.
Namespace attributes control the definition’s visibility. User-defined attributes provide a finer grain of visibility control.
Every package P has a predefined, anonymous namespace PackageInternalP. That
namespace is attached to all definitions with the internal attribute in that package. Package P’s
scope includes an implicit use namespace(PackageInternalP)
definition around the package that grants access to these definitions from within the package only.
Every class C has a predefined, anonymous namespace ClassInternalC. That namespace
is attached to all definitions with the private attribute in that class. Class C’s scope includes
an implicit use namespace(ClassInternalC) definition around
the class that grants access to these definitions from within that class only. private can only be used inside
a class.
Namespace attributes, including user-defined namespaces, are additive; if several are given for a definition, then that
definition is put into each of the designated namespaces. Thus, a single definition may define a name in two or more namespaces
namespace1 and namespace2 by listing the namespaces
as attributes: namespace1 namespace2 var x.
Such multiple definitions are aliases of each other; there is only one storage location x.
A definition of a name id is always put into the namespaces explicitly specified in the definition’s attributes. In addition, the definition may be placed in additional namespaces according to the rules below:
public namespace.Definitions of top-level entities in a package can only be placed in the namespace public or in namespaces
(including internal) defined within that package. See rationale.
Visibility modifier attributes control the definition’s visibility in several special cases.
An indexable definition can be accessed using the default [] operator. A nonindexable definition cannot
be accessed using this operator. Non-public definitions cannot be indexable.
The default for fixed properties is nonindexable and for dynamic
properties is indexable. One can make a fixed property indexable by making it enumerable. There is no way
to make a user-defined fixed property indexable but not enumerable. There is also no way to make a dynamic property
nonindexable.
enumerableAn enumerable definition can be seen by the for-in iteration statement. A non-enumerable
definition cannot be seen by such a statement. enumerable implies indexable.
The default for fixed properties is non-enumerable and for dynamic
properties is enumerable. There is no way to make a user-defined dynamic property non-enumerable.
explicitexplicit is used to add definitions to a package P without having them conflict with definitions
in other packages that import package P. explicit prevents the definition from being accessed as a
top-level variable when a package is imported. The definition can still be accessed as a property
of an object. For example,
package My.P1 {
  const c1 = 5;
  explicit const c2 = 7;
}
package My.P2 {
  import P = My.P1;  // Imports My.P1 without qualification
  c1;                // OK; evaluates to 5
  c2;                // Error: c2 not defined because explicit variables are not shared
  P.c2;              // OK: explicit properties are visible
}
compileIf the compile attribute is given on a const definition of C, then C’s
value must be a compile-time constant, and C itself will be
considered to be a compile-time constant usable in other compile-time
expressions. When the const definition is a class member, the compile attribute implies static.
The compile attribute is implicit in class, interface, and
namespace definitions, but may also be specified explicitly on these. The compile attribute cannot
be given on var or function definitions.
A const definition with the compile attribute can be accessed by non-compile-time expressions
throughout its scope, including forward-referenced ones. On the other hand, the expression defining the value of a compile const
definition cannot contain forward references.
Class modifier attributes apply to the definition of a class C itself. They may only be used on definitions of classes.
finalIf a class C is defined using the final attribute, then any attempt to define a subclass of C
signals an error.
Note that final is also a member modifier — when used on a class member,
final makes that member nonoverridable. If final is used on a class member that is itself a class,
then it acts like a class modifier instead of a member modifier — it prevents the inner class from being subclassed.
dynamicInstances of a dynamic class C or its subclasses can contain dynamic
properties. Other instances cannot contain dynamic properties.
Member modifier attributes modify a class or interface member definition’s semantics with respect to a class hierarchy. They may only be used on a definition of a member M of a class or interface C. They cannot be used on definitions that, for example, create local variables inside a function.
static, constructor, operator, abstract, virtual, and
  finalThe static (or compile, which implies static) attribute makes M be a
global member of C.
The constructor attribute makes M be a global member of C that constructs new instances
of C.
The operator attribute makes M be an operator override.
M must be a function definition using one of the special quoted operator names and signatures.
The abstract, virtual, and final attributes make M be an instance member
of C.
The final attribute prevents subclasses from defining their own members with the name M (unless
they can’t see this M, in which case they can define an independent M). virtual and abstract
allow subclasses to override M. In addition, abstract causes an error to be signaled if an attempt
is made to get or set the value of this class’s M. Note that, if M is abstract, a subclass
does not have to implement M, but if it doesn’t then it can’t access it.
The default setting for the definition of a member M of a class or interface named C is:
| Default Attribute | Kind of Member M | 
|---|---|
| constructor | functionC | 
| abstract | functionF without a body, where the name F differs from C | 
| virtual | functionF with a body, where the name F differs from C | 
| final | varandconstdefinitions | 
| static | class,interface, andnamespacedefinitions | 
These attributes may not be used on an export definition, since export reuses the original member’s
setting.
Note that final is also a class modifier — when used on a class member
M, final prevents M from being subclassed rather than making M be a nonoverridable
instance member of C.
overrideThe override attribute reports errors; it has no other effect on the behavior of the program. The override
attribute can only be used on definitions in a class and describes the programmer’s intent to either override or not
override a member from a superclass. If the actual behavior, as defined by the namespace
defaulting and overriding rules, differs, then an error is signaled.
The table below describes the behavior of when a definition of a member M with name id is placed in a class C:
| Override attribute given | ||||
|---|---|---|---|---|
| None | overrideoroverride(true) | override(undefined) | override(false) | |
| M overrides a member in some superclass according to the namespace defaulting and overriding rules | Error | OK | OK | Error | 
| M does not override anything but there exists an ancestor of C with a member with name id visible at the point of definition of M | Error | Error | OK | OK | 
| M does not override anything and no ancestor of C has a member with name id visible at the point of definition of M | OK | Error | OK | OK | 
The middle case arises for example when an ancestor of a class C defines a public member named
X and class C attempts to define a private member named X.
An attribute whose value is true causes the definition or directive to be evaluated normally. An attribute
whose value is false causes the definition or directive to be skipped; the remaining attributes and the body
of the definition or directive are not evaluated. These are useful for turning definitions on and off based on configuration
settings, such as:
compile const debug = true;
compile const nondebug = !debug;
debug var nCalls = 0;
debug function checkConsistency() {...}
weakThe weak attribute, which can be used only on var definitions, makes the defined variable be
  a weak reference. If there is no way to reference the variable’s value except via weak references, then the system may,
  at its option and at any time, replace the variable’s value with null. The variable’s type must allow null.
prototypeThe prototype attribute, which can only be used on a function definition, imposes JavaScript 1.5-like prototype
semantics on that function. If such a function is an instance member then it:
this in the same manner as JavaScript 1.5;this parameter instead of just instances of the enclosing class;prototype global member;prototype global member;super within this function.If such a function is not an instance member then it:
this in the same manner as JavaScript 1.5;By default, the prototype attribute is set on any unchecked function.
It can be set explicitly on other functions as long as they are not getters, setters, or constructors.
unusedThe unused attribute is a hint that the definition is not referenced anywhere. Referencing the definition
will generate an error.
A user-defined attribute may be defined using a compile const definition or other definitions that define
constants. All attributes must be compile-time constants. For example:
compile const ipriv = internal static;
explicit namespace Version1;
explicit namespace Version2;
internal compile const Version1and2 = Version1 Version2;
class C {
  ipriv var x;                          // Same as internal static var x;
  Version1and2 var simple;              // Same as Version1 Version2 var simple;
  Version2 var complicated;
  ipriv const a:Array = new Array(10);
  private var i;
  for (i = 0; i != 10; i++) a[i] = i;
}
A definition extends an activation frame with one or more bindings of qualified
names to values. The bindings are generally visible from the activation frame’s scope.
However, a definition may be invisible or partially invisible inside its scope either because it is shadowed by a more local
definition or it uses a namespace that is not used. The name lookup rules
specify the detailed behavior of accessing activation frame bindings.
Each definition or declaration D of a name n has an implicit or explicit scope attribute, which designates a scope S to which the definition applies. Any of S’s activation frames will contain a binding for n as soon as S is entered. That binding starts in the following state:
var n definition D
    without a type or attributes is initialized to the value undefined upon entry into S.function n definition D
    without types or attributes is initialized to its closure upon entry into S instead of at the time D
    is executed.class or  interface definition D of a name n
    in scope S binds n to an opaque value V of type Type upon entry into S.
    V may be used as a type to declare variables, but all other operations are prohibited. V becomes
    the actual class or interface object at the time the definition is executed, after which point
    instances of V may be created and subclasses may be derived from V.Accessing an activation frame binding in the uninitialized state is an error. If this happens, implementations are encouraged to throw an exception, but may return a value V if they can prove that the definition would assign the value V to the binding.
In general, it is not legal to rebind the same name in the same namespace within an activation frame A. There are a couple exceptions:
var definitions (which may be hoisted) are allowed in a regional
    scope as long as all such definitions have no type and no attributes and strict
    mode is not in effect.In addition, if a name n is defined in a scope S inside regional scope R, then it is not permitted to access a definition of n made outside of R from anywhere inside R. Also, two nested scopes S1 and S2 located inside the same regional scope R cannot both define n (S1, S2, and R may be the same scope). In either of these situations, n may be hoisted; if hoisting is not allowed, an error occurs. For example,
const b:Integer = 1;
function f(c:Boolean):Integer {
  const a = b;  // Error: b is defined inside the local scope below, which prevents accesses to global b
                // from anywhere inside the regional scope
  if (c) {
    const b:Integer = a + 10;  // OK to hide the global b from here.
    return b;
  }
  return a;
}
function g(c:Boolean):Integer {
  const b = 3;  // OK to hide the global b from here.
  if (c) {
    const b:Integer = 10;  // Error: can’t redefine b inside the same regional scope.
    return b;
  }
  return b;
}
function h(c:Boolean):Integer {
  if (c) {
    const b:Integer = 10;  // OK to hide the global b from here.
    return b;
  } else {
    const b:Integer = 42;  // OK: Two independent local definitions of b.
    return b;
  }
}
To help catch accidental redefinitions, binding a qualified name q::n
in activation frame A when there is already a binding r::n in A causes
an error if both namespaces q and r are used at the point of the definition of q::n
and the bindings are not aliases of each other. This prevents the same name from being used for both public and
private variables in the same class. Two bindings sharing the same name but with different namespaces may still
be introduced into an activation frame, but only by code that does not use one or both of the namespaces.
In the example below the comments indicate the scope and namespace of each definition:
var a0;                  // Public global variable
internal const a1 = true;// Package-visible global variable
private var a2;          // Error: private 
can only be used inside a class
public var a3 = b1;      // Public global variable
if (a1) {
  var b0;                // Local to this block
  var b1;                // Hoisted to the global level because of the reference to b1 in the definition of a3
}
if (a1) {
  var b0;                // Local to this block
}
public function F() {    // Public global function
  var c0;                // Local to this function
  internal var c1;       // Local to this function 
(may generate a style warning)
  public var c2;         // Local to this function 
(may generate a style warning)
}
class C {                // Public global class
  var e0;                // Public class instance variable
  private var e1;        // Class-visible class instance variable
  internal var e2;       // Package-visible class instance variable
  public var e3;         // Public class instance variable
  static var e4;         // Public class-global variable
  private static var e5; // Class-visible class-global variable
  internal static var e6;// Package-visible class-global variable
  public static var e7;  // Public class-global variable
  if (a1) {
    var f0;              // Local to this block
    private var f1;      // Local to this block 
(may generate a style warning)
  }
  public function I() {} // Public class method
}
Sometimes it is useful to add a namespace to a prior definition of a name (perhaps inherited from a superclass) or rename a name inherited from a superclass or imported package. The export definition provides a facility to make an alias of an existing name:
The first FunctionName is the new name. If the second FunctionName is provided then it is the existing name; otherwise, the first FunctionName is also the existing name. If one of the FunctionNames is a getter or setter, then the other one must be a getter or setter, respectively.
A new name is an exact alias of the old name rather than a separate value or entity. Thus, if method A is renamed as method B and B is subsequently overridden by B', then B' really overrides A.
Here are a few examples of definition renaming:
package Light {
  const red = 1;
  const green = 2;
  const blue = 4;
  const white = red + green + blue;
}
package Saber {
  import Light;
  namespace New;
  namespace Improved;
  export white; // Re-export Light’s white
  New export green; // Re-export Light’s green, but only in the new version
  class C {
    internal var size;
    function color() {}
  }
  interface I1 {
    function get length() {}
  }
  interface I2 {
    function get length() {}
  }
  class D extends C implements I1, I2 {
    var inertia;
    export size; // Make size public in instances of D
    export colour = color; // Make alias for British users
    function mispelled() {}; // Oops! Saber was already released and it’s too late to remove this
    Improved export misspelled = mispelled; // Users of the improved version can use the good name
    export length = I2::length; // Resolve name conflict in favor of I2
  }
}
Should we have a protected Attribute? It has been omitted for now to keep
  the language simple, but there does not appear to be any fundamental reason why it could not be supported. If we do support
  it, it might be better to choose the C++ protected concept (visible only in class and subclasses); the Java
  protected concept (visible in class, subclasses, and the original class’s package) could be represented as
  internal protected.
| Waldemar Horwat Last modified Friday, April 12, 2002 |    |