April 2002 Draft
JavaScript 2.0
Core Language
Functions
previousupnext

Monday, December 17, 2001

Syntax

FunctionDefinition 
   FunctionDeclaration Block
|  FunctionDeclaration Semicolon

The Block contains the function body and is evaluated only when the function is called. If the Block is omitted, the function is assumed to be abstract.

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 or interface.

FunctionDeclaration  function FunctionName FunctionSignature
FunctionName 
   Identifier
|  get [no line break] Identifier
|  set [no line break] Identifier
|  String

A FunctionDeclaration can specify a function, getter (if its name is preceded by get), or setter (if its name is preceded by set), or an operator override (if the FunctionDeclaration is preceded by the operator attribute). A FunctionName can be a String only for operator overrides.

Function Signatures

FunctionSignature  ParameterSignature ResultSignature
ParameterSignature  ( Parameters )

A FunctionSignature gives the names and the types of the function’s parameters and result.

Parameter Declarations

A function may take zero or more required parameters, followed by zero or more optional parameters and either an optional rest parameter followed by zero or more named parameters or a named rest parameter:

Parameters 
   «empty»
|  AllParameters
AllParameters 
   Parameter
|  Parameter , AllParameters
|  OptionalParameters
OptionalParameters 
   OptionalParameter
|  OptionalParameter , OptionalParameters
|  RestAndNamedParameters
RestAndNamedParameters 
   NamedParameters
|  RestParameter
|  RestParameter , NamedParameters
|  NamedRestParameter
NamedParameters 
   NamedParameter
|  NamedParameter , NamedParameters

Individual parameters have the forms:

Parameter 
   TypedIdentifierallowIn
|  const TypedIdentifierallowIn
OptionalParameter  Parameter = AssignmentExpressionallowIn
TypedInitialiser  TypedIdentifierallowIn = AssignmentExpressionallowIn
NamedParameter 
   named TypedInitialiser
|  const named TypedInitialiser
|  named const TypedInitialiser
RestParameter 
   ...
|  ... Parameter
NamedRestParameter 
   ... named Identifier
|  ... const named Identifier
|  ... named const 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. An optional parameter’s AssignmentExpression is evaluated only if no argument is given for that parameter.

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 parameter is prefixed with named, then the parameter is matched by name rather than by position. Named parameters are always optional and must have initializers.

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.

A function call may specify some positional arguments and some named arguments. Required and optional parameters can only match positional arguments. Named parameters can only match named arguments.

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 const using the parameter’s type (which must be Array or a subtype of Array), or type Object[] if not provided. If the rest parameter is named, then the parameter’s type is always Array and cannot be specified explicitly.

The remaining positional arguments are stored as elements of the rest array with numeric indices starting from 0. If the rest parameter is not named, then there must be no remaining named arguments. Otherwise, extra named arguments are allowed and are stored as named properties of the rest array.

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

ResultSignature 
   «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".

On the other hand, an optional, named, or rest parameter’s AssignmentExpression may refer to the values of prior parameters:

function f(a:Integer, b:Integer = a, c:Integer = b):Integer {
  return a + b + c;
}

f(3);        // Returns 9
f(3, 4);     // Returns 11
f(3, 4, 10); // Returns 17

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 positional 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 a positional argument remaining, use the value of the positional argument. If there are no remaining positional arguments, then evaluate the first parameter’s AssignmentExpression and let it be the first parameter’s value.
  5. If the first parameter is named and there is a named argument with a matching argument name, then use the value of that named argument. Otherwise, evaluate the first parameter’s AssignmentExpression and let it be the first parameter’s value.
  6. Implicitly coerce the argument (or default) value to type t and bind the parameter’s Identifier to the result.
  7. Repeat steps 2-6 for each additional required, optional, and named parameter.
  8. If there is a RestParameter and one or more of the remaining arguments is named, raise an error.
  9. If there is a RestParameter with an Identifier, bind that Identifier to an array of the remaining positional arguments using indices starting from 0.
  10. If there is a NamedRestParameter, bind its Identifier to an array of the remaining positional arguments using indices starting from 0 as well as the remaining named arguments stored using named properties.
  11. If there is no RestParameter or NamedRestParameter and any arguments remain, raise an error unless the function is unchecked.
  12. Evaluate the body.
  13. Get the saved type r that was the result of evaluating the result TypeExpression at the time the function was defined.
  14. 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 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 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 JavaScript 1.5.

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, December 17, 2001
previousupnext