JavaScript 2.0
Core Language
Definitions
previousupnext

Tuesday, February 15, 2000

Introduction

Definitions introduce new constants, variables, functions, and classes. All definitions can be preceded by zero or more attributes using the following syntax:

AnnotatedDefinitionw  Attributes Definitionw
Attributes 
   «empty»
|  FixedAttribute [no line break] Attributes
|  Identifier [no line break] Attributes
FixedAttribute 
   private
|  public
|  final
Definitionw 
   VariableDefinition Semicolonw
|  FunctionDefinitionw
|  ClassDefinition

Attributes

A definition attribute is an identifier that modifies the definition. Attributes can specify a definition's visibility, semantics, and other hints. A JavaScript program may also define and subsequently use its own attributes.

The table below summarizes the predefined attributes.

Category Attribute Behavior
Visibility local The definition is local in the enclosing block.
scope The definition applies to the enclosing scope.
global The definition applies to the enclosing package and is visible only inside this package.
private The definition creates a member of the enclosing class. The defined member is visible only inside that class. If there is no enclosing class, private is the same as global.
package The definition creates a member of the enclosing class. The defined member is visible only inside the enclosing package. If there is no enclosing class, package is the same as global.
public   The definition creates a member of the enclosing class. The defined member is visible anywhere. If there is no enclosing class, the definition applies to the enclosing package and is visible in any package that imports this package.
Semantic   static The definition creates a global member (rather than an instance member) of the enclosing class.
instance The definition creates an instance member (rather than a global member) of the enclosing class.
final   The definition cannot be overridden in subclasses.
Hint override The definition overrides a member of a superclass.
mayOverride   The definition may override a member of a superclass.
compile Compiler hint that the definition may be processed at compile time.
unused Compiler hint that the definition is not used.

Visibility Attributes

A visibility attribute describes the scope to which a definition applies as well as the definition's visibility outside that scope. A visibility attribute may be user-defined, in which case it can also indicate that the definition is visible in other packages only when those packages import a specific version of this package.

The local attribute applies the definition to the enclosing Block. If the enclosing block is a class, the definition does not appear as a member of that class.

The scope attribute applies the definition to the enclosing scope. If the enclosing scope is a class, the definition will appear as a member of that class; that member will be visible only inside the enclosing package (as though it had package visibility).

The global attribute applies the definition to the enclosing package.

The private, package, public, and user-defined version attributes apply the definition to the enclosing class or to the current package if there is no enclosing class.

The default visibility is scope.

There is a slight syntactic ambiguity between using package as a block attribute and defining a new package.

Semantic Attributes

The static attribute makes the definition create a global member rather than an instance member of the enclosing class. The instance attribute reverses this -- it makes the definition create an instance member of the enclosing class. The final attribute prevents subclasses from overriding this definition.

These three attributes may only be used on definitions that apply to a class. They cannot be used on definitions that, for instance, create local variables inside a function.

Hint Attributes

The override and mayOverride attributes control warnings. Normally defining a class member with the same name as a visible member of a superclass generates a warning. The override attribute reverses the sense of the warning so that the warning will be generated if there is no visible member of a superclass with the same name. The mayOverride attribute turns off this warning altogether.

The compile attribute is a hint that the definition may be evaluated early. See compiler blocks.

The unused attribute is a hint that the definition is not referenced anywhere. Referencing it will generate a warning.

User-Defined Attributes

Any constant defined in an enclosing scope is also a potential attribute. That constant's value must be an attribute object, which can be obtained either from another attribute or by calling one of the attribute-creating functions such as Version. For example, the following code creates aliases priv and loc of the attributes private and local:

compile {
  const priv = private;
  const loc = local;
  const V1 = Version("1.0","");
  const V2 = Version("2.0","1.0");
}

class C {
  priv var x;
  V1 var simple;
  V2 var complicated;
  priv static const a:Array = new Array(10);

  loc var i;
  for (i = 0; i != 10; i++) a[i] = i;
}

An implementation may require that user-defined attributes be defined early (in compiler blocks or using the compile attribute).

Extent

Each definition has a particular static and dynamic extent. The static extent of a definition is the region of source code where the definition is visible. The dynamic extent is the time interval during which the defined constant, variable, function, or class may be accessed.

The rules for determining the extent of a definition differ depending on whether the defined entity is a class member or not.

Non-Class Members

The static extent of a definition D is specified by its visibility attribute, which designates a scope (or set of scopes) A where the definition is visible. If there is a subscope B in A that defines an entity E with the same name as D and the definition E is actually executed, then the inner definition E shadows the outer one and definition D is not visible inside B.

In general, the dynamic extent of a definition D begins when the definition is executed and ends when its static extent scope is exited. There are a couple of exceptions to this rule for compatibility with JavaScript 1.5:

Situations may arise where an inner definition will shadow an outer definition but the inner definition's static extent has not yet begun. In the example below, function f shadows the global b but tries to access the inner b before its dynamic extent begins (at the time the const  b:Integer = 8 statement is executed). This is illegal, but an implementation is not required to diagnose such an error (which may be difficult, especially if the inner b is defined conditionally). The effects of executing such a program are undefined.

const b:Integer = 7;

function f():Integer {
  function g():Integer {return b}

  var a = g();
  const b:Integer = 8;
  return g() - a;
}

In general, it is not legal to define the same entity twice within a scope A without exiting A in the interim. There are a couple of exceptions:

Class Members

Examples

In the example below the comments indicate the scope and visibility of each definition:

var a0;                 // Package-visible global variable
local var a1;           // Package-visible global variable
private var a2 = true;  // Package-visible global variable
package var a3;         // Package-visible global variable
public var a4;          // Public global variable

if (a1) {
  var b0;               // Package-visible global variable
  local var b1;         // Local to this block
  private var b2;       // Package-visible global variable
  package var b3;       // Package-visible global variable
  public var b4;        // Public global variable
}

public function F() {   // Public global function
  var c0;               // Local to this function
  local var c1;         // Local to this function
  private var c2;       // Package-visible global variable
  package var c3;       // Package-visible global variable
  public var c4;        // Public global variable
}

function G() {          // Package-visible global function
  var d0;               // Never defined because G isn't called
  private var d1;       // Never defined because G isn't called
  package var d2;       // Never defined because G isn't called
  public var d3;        // Never defined because G isn't called
}

class C {               // Package-visible global class
  var e0;               // Package-visible class instance variable
  private var e1;       // Class-visible class instance variable
  package var e2;       // Package-visible class instance variable
  public var e3;        // Public class instance variable
  static var e4;        // Package-visible class-global variable
  private static var e5;// Class-visible class-global variable
  package static var e6;// Package-visible class-global variable
  public static var e7; // Public class-global variable
  local var e8;         // Local to class C's block

  function H() {        // Package-visible class function
    var f0;             // Local to this function
    private var f1;     // Class-visible class variable
    package var f2;     // Package-visible class variable
    public var f3;      // Public class variable
  }
  public function I() {}// Public class method

  H();
}

F();

A static subset of JavaScript 2.0 may disallow definitions inside a function F that define entities in a scope outside F. This would disallow functions F, G, and H above.

Discussion

Should we have a protected Visibility? 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, should we choose the C++ protected concept (visible only in class and subclasses) or the Java protected concept (visible in class, subclasses, and the original class's package)?


Waldemar Horwat
Last modified Tuesday, February 15, 2000
previousupnext