ECMAScript 4 Netscape Proposal
Core Language
Functions
previousupnext

Monday, April 28, 2003

Syntax

FunctionDefinition  function FunctionName FunctionCommon
FunctionName 
   Identifier
|  get [no line break] Identifier
|  set [no line break] Identifier
FunctionCommon  ( Parameters ) Result Block

Like other definitions, a function definition may be preceded by one or more attributes, which affect the function’s scope, namespace, and semantics. Every function (except a getter or a setter) is also a value and has type Function.

Unless a function f is defined with the prototype attribute (either explicitly or by default because f is unchecked), that function does not define a class, f’s name cannot be used in a new expression, and f cannot refer to this unless f is an instance method or constructor of a class.

A FunctionDefinition can specify a function, getter (if its name is preceded by get), or setter (if its name is preceded by set).

Parameters give the names and the types of the function’s parameters. Result gives the type of the function’s result. The Block contains the function body and is evaluated only when the function is called.

Parameter Declarations

A function may take zero or more parameters and an optional rest parameter. Optional parameters may follow but not precede required parameters (this condition is not in the grammar but is checked by the formal semantics).

Parameters 
   «empty»
|  NonemptyParameters
NonemptyParameters 
   ParameterInit
|  ParameterInit , NonemptyParameters
|  RestParameter

Individual parameters have the forms:

Parameter  ParameterAttributes TypedIdentifierallowIn
ParameterAttributes 
   «empty»
|  const
ParameterInit 
   Parameter
|  Parameter = AssignmentExpressionallowIn
RestParameter 
   ...
|  ... ParameterAttributes Identifier

The TypeExpression gives the parameter’s type and defaults to type Object. The TypeExpression must evaluate to a type other than Never.

If a Parameter is followed by a =, then that parameter is optional. If a function call does not provide an argument for an optional parameter, then that parameter is set to the value of its AssignmentExpression, implicitly coerced to the parameter’s type if necessary. The AssignmentExpression must be a compile-time constant.

If a Parameter is prefixed with const, then the parameter is declared using const instead of var. The effect is that the parameter’s value cannot be changed from within the function. Without the const, the function can change the parameter’s value, which, however, has no effect on the argument.

If a function call does not provide an argument for a required Parameter, then an error occurs unless the function is unchecked, in which case the parameter gets the value undefined, implicitly coerced to the parameter’s type if necessary.

The parameters’ Identifiers are local variables with types given by the corresponding TypeExpressions inside the function’s Block. Code in the Block may read and write these variables. Arguments are passed by value, so writes to these variables do not affect the passed arguments’ values in the caller.

Attempting to define a function with two different parameters with the same name is an error.

Rest Parameter

If the ... is present, the function accepts arguments not matched by any of the other listed parameters. If a parameter is given after the ..., then that parameter’s identifier is bound to an array of all remaining arguments. That identifier is declared as a local var or const using the type Array. The remaining arguments are stored as elements of the rest array with numeric indices starting from 0.

Each unchecked function also has a predefined const arguments local variable which holds an array (of type Array) of all arguments passed to this function.

Result Type

Result 
   «empty»
|  : TypeExpressionallowIn

The function’s result type is TypeExpression, which defaults to type Object if not given. The TypeExpression must evaluate to a type.

If the function does not return a useful value, it’s good practice to set TypeExpression to Void to document this fact. If the function cannot return at all (it either always falls into an infinite loop or throws an exception), then it’s good practice to set TypeExpression to Never to document this fact; this also lets the compiler know that code after a call to this function is unreachable, which can help cut down on spurious warnings.

Evaluation Order

A function’s parameter and result TypeExpressions are evaluated at the time the function definition or declaration is executed. These types are then saved for use in argument and result coercions at the time the function is called.

The static and dynamic extent of a parameter includes all subsequent parameters’ and the result type’s TypeExpressions and AssignmentExpressions. However, the case where a subsequent parameter’s or the result type’s TypeExpression or AssignmentExpression references a prior parameter is reserved for a future language extension. For now, an implementation should raise an error in this case:

const t = Integer;
function choice(a:Boolean, t:Type, c:t, d:t):t {
  return a ? c : d;
}

This definition of choice should (for now) be an error and not:

function choice(a:Boolean, t:Type, c:Integer, d:Integer):Integer {
  return a ? c : d;
}

The intent is that a future language extension might make the first definition of choice legal and permit calls to it like choice(true,String,"Be","Not Be"), which would return "Be".

When a function is called, the following list indicates the order of evaluation of the various expressions in a FunctionDefinition. These steps are taken only after all of the argument names and values have been evaluated.

  1. If the function is unchecked, bind the arguments local variable to an array of all arguments and their names.
  2. Get the saved type t that was the result of evaluating the first parameter’s TypeExpression at the time the function was defined.
  3. If the first parameter is required and no argument has been supplied for it, then raise an error unless the function is unchecked, in which case let undefined be the first parameter’s value.
  4. If the first parameter is optional and there is an argument remaining, use the value of the argument. If there are no remaining arguments, then evaluate the first parameter’s AssignmentExpression and let it be the first parameter’s value.
  5. Implicitly coerce the argument (or default) value to type t and bind the parameter’s Identifier to the result.
  6. Repeat steps 2-5 for each additional parameter.
  7. If there is a RestParameter with an Identifier, bind that Identifier to an array of the remaining arguments using indices starting from 0.
  8. If there is no RestParameter and any arguments remain, raise an error unless the function is unchecked.
  9. Evaluate the body.
  10. Get the saved type r that was the result of evaluating the result TypeExpression at the time the function was defined.
  11. Implicitly coerce the result to type r and return it.

Getters and Setters

If a FunctionName contains the keyword get or set, then the defined function is a getter or a setter.

A getter must not take any parameters. Unlike an ordinary function, a getter is invoked by merely mentioning its name without an Arguments list in any expression except as the destination of an assignment. For example, the following code returns the string “<2,3,1>”:

var x:Integer = 0;
function get serialNumber():Integer {return ++x}

var y = serialNumber;
return "<" + serialNumber + "," + serialNumber + "," + y + ">";

A getter must either evaluate a return statement or throw an exception; it cannot fall off the end without returning a value.

A setter must take exactly one required parameter. Unlike an ordinary function, a setter is invoked by merely mentioning its name (without an Arguments list) on the left side of an assignment or as the target of a mutator such as ++ or --. The setter should not return a value and should be declared as returning type Void or Never. The result of an assignment expression is the argument passed to the setter. For example, the following code returns the string “<1,2,42,43>”:

var x:Integer = 0;
function get serialNumber():Integer {return ++x}
function set serialNumber(n:Integer):Void {x=n}

var s = "<" + serialNumber + "," + serialNumber;
s += "," + (serialNumber = 42);
return s + "," + serialNumber + ">";

A setter cannot return a value; it may invoke a return statement as long as that statement does not supply an expression.

A setter can have the same name as a getter in the same lexical scope. A getter or setter cannot be extracted from its variable, so the notion of the type of a getter or setter is vacuous; a getter or setter can only be called.

Contrast the following:

var x:Integer = 0;
function f():Integer {return ++x}
function g():Function {return f}
function get h():Function {return f}

f;     // Evaluates to function f
g;     // Evaluates to function g
h;     // Evaluates to function f (not h)
f();   // Evaluates to 1
g();   // Evaluates to function f
h();   // Evaluates to 2
g()(); // Evaluates to 3

See also the discussion of getter and setter syntax.

Unchecked Functions

An unchecked function relaxes argument checking. Unchecked function definitions are provided for compatibility with ECMAScript 3.

A function definition is unchecked if all of the following are true:

An unchecked function also has the prototype attribute set by default.


Waldemar Horwat
Last modified Monday, April 28, 2003
previousupnext