March 1999 Draft
JavaScript 2.0
Declarations
previousupnext

Wednesday, March 24, 1999

Declaration Kinds

Several different kinds of declarations can be present in JavaScript 2.0 programs:

Variable declarations
VariableDefinition 
   [Visibilityvar [TypeExpressionIdentifier [= AssignmentExpression, ... , [TypeExpressionIdentifier [= AssignmentExpression;
|  [Visibilityconst [TypeExpressionIdentifier = AssignmentExpression , ... , [TypeExpressionIdentifier = AssignmentExpression ;
Function declarations
FunctionDefinition 
   [Visibility] [getter | setterfunction Identifier ( Parameters ) [TypeExpressionBlock
|  [Visibilitytraditional function Identifier ( Identifier , ... , Identifier ) Block
Field, method and constructor declarations
MemberDefinition 
   [Visibilityfield [TypeExpressionIdentifier [= AssignmentExpression, ... , [TypeExpressionIdentifier [= AssignmentExpression;
|  [Visibility] [getter | setter] [final] [overridemethod Identifier ( Parameters ) [TypeExpressionBlock
|  [Visibility] [getter | setter] [final] [overridemethod Identifier ( Parameters ) [TypeExpression;
|  [Visibilityconstructor Identifier ( Parameters ) Block
Class declarations
ClassDefinition 
   [Visibilityclass Identifier [extends TypeExpressionBlock
|  [Visibilityclass extends TypeExpression Block
Version declarations
VersionDefinition 
   [Visibilityversion Version [> VersionList;
|  [Visibilityversion Version [= Version;

Scope Rules

All of these declarations share several common scoping rules:

  1. A declaration without a Visibility prefix declares an entity in the current Block scope (which may be the current package if the declaration is at the top level of a Program, or a class if the declaration is at the top level of a ClassDefinition's Block); the declared name has package visibility. A declaration with a Visibility prefix applies either to the current package (if outside a ClassDefinition's Block) or to the current class (if inside a ClassDefinition's Block), and the declared name has visibility specified by the Visibility prefix.
  2. A declaration that applies to a scope can be referenced lexically from anywhere within that scope unless shadowed by a more local declaration.
  3. A declaration that applies to a scope lasts until that scope is exited. No other declaration may be executed for the same identifier applying to the same scope (with the exceptions that both a getter and a setter may be defined with the same name and that versions have a namespace separate from other declarations).
  4. If code executing inside a scope s has already made an attempt to resolve identifier i and that resolution either bound i to a definition of i in a scope enclosing s or failed because i wasn't defined, then no declaration of i applying to scope s may be executed.

Rules 3 and 4 state that once an identifier is resolved to a variable or function in a scope, that resolution cannot be changed. This permits efficient compilation and avoids confusion with programs such as:

const integer b = 7;

function f() integer {
  function g() integer {return b}

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

Scopes

Most lexical scopes are established by Block productions in the grammar. Lexical scopes nest, and a declaration in an inner scope can shadow declarations in outer ones.

Declaration Visibility

A declaration with a Visibility prefix does not apply to the current Block. Instead, it declares either an entity at the top level of the current package (if outside a ClassDefinition's Block) or a member of the current class (if inside a ClassDefinition's Block). In addition to lifting the declaration out of the current scope in this way, Visibility also specifies the declaration's visibility from other packages or classes. Visibility can take one of the following forms:

Visibility   Access allowed from
private only within current class
package only within current package
public VersionsAndRenames   within any package that imports this package

Declarations at the top level of a Program or at the top level of a ClassDefinition's Block may omit Visibility, in which case they are treated as if they had package visibility. When used outside a ClassDefinition's Block, private is equivalent to package.

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

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

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

public function F() {   // Public global function
  var c0;               // Local to this function
  private var c1;       // Package-visible global variable
  package var c2;       // Package-visible global variable
  public var c3;        // 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 variable
  private var e1;       // Class-visible class variable
  package var e2;       // Package-visible class variable
  public var e3;        // Public class variable
  field e4;             // Package-visible instance variable
  private field e5;     // Class-visible instance variable
  package field e6;     // Package-visible instance variable
  public field e7;      // Public instance variable

  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
    private field f4;   // Class-visible instance variable
    package field f5;   // Package-visible instance variable
    public field f6;    // Public instance variable
  }
  public method I() {}  // Public class method

  H();
}

F();

Versioning Public Identifiers

A public declaration's identifier is exported to other packages. To help avoid accidental collisions between identifiers declared in different packages, identifiers can be selectively exported depending on the version requested by an importing package. An identifier declaration with a version number newer than that requested by the importer will not be seen by that importer. The versioning facilities also include additional facilities that allow robust removal and renaming of identifiers.

VersionsAndRenames describes the set of versions in which an identifier is exported, together with a possible alias for the identifier:

VersionsAndRenames 
   [VersionRange [: Identifier, ... , VersionRange [: Identifier]]
VersionRange 
   Version
|  [Version.. [Version]

Suppose a client package C imports version V of package P that exports identifier N with some VersionsAndRenames. If the VersionsAndRenames's VersionRange includes version V, then package C can use the corresponding Identifier alias to access package P's N. If the Identifier alias is omitted, then package C can use N to access package P's N. Multiple VersionRanges operate independently.

In most cases VersionsAndRenames is just a Version name (a string):

public "1.2" const z = 3;

If VersionsAndRenames is omitted, the default version "" is assumed.

Discussion

Scopes

Do we want to collapse all block scopes into one inside functions? On one hand this complicates the language conceptually and surprises Java and C++ programmers. On the other hand, this would match JavaScript 1.x better and simplify closure creation when a closure is created nested inside several blocks in a function.

Visibilities

Should we make private illegal outside a class rather than making it equivalent to package?

Should we introduce a local Visibility prefix that explicitly means that the declaration is visible locally? This wouldn't provide any additional functionality but it would provide a convenient name for talking about the four kinds of visibility prefixes.

What should the default visibilities be? The current defaults are loosely modeled after Java:

Definition Location Default visibility
Package top level package (equivalent to local in this case)
Inside a statement outside a function or class   local
Function or method code's top level local
Inside a statement inside a function or method   local
Class declaration block's top level package
Inside a statement inside a class declaration block   local

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 Wednesday, March 24, 1999
previousupnext