Google Dart Language Specification II – Variables, Functions and Classes

< PREV: Google Dart Language Specification I

Google Dart Language Specification II – Variables, Functions & Classes

[The current version (0.05) was released November 14, 2011. See the specification’s change log (section 1.2) for a list of differences between versions

Variables

Variables are storage locations in memory.

variableDeclaration:
declaredIdentifier (‘,’ identifier)*
;

initializedVariableDeclaration:
declaredIdentifier (‘=’ expression)? (‘,’ initializedIdentifier)*
;

initializedIdentifierList:
initializedIdentifier (‘,’ initializedIdentifier)*
;

initializedIdentifier:
identifier (‘=’ expression)?
;

declaredIdentifier:
finalVarOrType identifier
;

finalVarOrType:
final type?
| var
| type
;

A variable that has not been initialized has the initial value null.
A final variable is a variable whose declaration includes the modifier final. A final variable can only be assigned once, when it is initialized, or a compile-time error occurs.

A static variable is a variable that is not associated with a particular instance, but rather with an entire library or class.

A variable that is marked both static and final must be initialized to a compile-time constant or a compile-time error occurs.

Why tie together two orthogonal concepts like static and final by requiring the use of constants? Because we do not want a language where one tends to define expensive initialization computations, causing long application startup times. This is especially crucial for Dart, which is designed for coding client applications.
One time initializations using constants should incur negligible cost at run time.

If a variable declaration does not explicitly specify a type, the type of the declared variable(s) is Dynamic, the unknown type.

A top-level variable is implicitly static. It is a compile-time error to preface a top level variable declaration with the built-in identifier static. A top level variable marked final must be initialized to a compile-time constant or a compile-time error occurs.

Functions

Functions abstract over executable actions.

functionSignature:
returnType? identifier formalParameterList
;

returnType:
void
| type
;

functionBody:
‘=>’ expression ‘;’
| block
;

block:
‘{‘ statements ‘}’
;

Functions include function declarations, methods, getters, setters and function literals.

All functions have a signature and a body. The signature describes the formal parameters of the function, and possibly its name and return type. The body is a block statement containing the statements executed by the function. A function body of the form => e is equivalent to a body of the form {return e;}.

If the last statement of a function is not a return statement, the statement return null; is implicitly appended to the function body.

Because Dart is optionally typed, we cannot guarantee that a function that does not return a value will not be used in the context of an expression. Therefore, every function must return a value. See the discussion around the return statement.

Function Declarations

A function declaration is a function that is not a method, getter, setter or function literal. Function declarations include library functions, which are function declarations at the top level of a library, and local functions, which are functions declarations declared inside other functions.

A function declaration of the form T0 id(T1 a1, …, Tn an, [Tn+1 xn+1 = d1, …, Tn+k xn+k = dk]){s} is equivalent to a variable declaration of the form final F id = (T1 a1, …, Tn an, [Tn+1 xn+1 = d1, …, Tn+k xn+k = dk]){s} where F is the function type alias typedef T0 F(T1 a1, …, Tn an, [Tn+1 xn+1, …, Tn+k xn+k]).
Likewise, a function declaration of the form id(T1 a1, …, Tn an, [Tn+1 xn+1 = d1, …, Tn+k xn+k = dk]){s} is equivalent to a variable declaration of the form final F id = (T1 a1, …, Tn an, [Tn+1 xn+1 = d1, …, Tn+k xn+k = dk]){s} where F is the function type alias typedef F(T1 a1, …, Tn an, [Tn+1 xn+1, …, Tn+k xn+k]).

Some obvious conclusions:

A function declaration of the form id(T1 a1, …, Tn an, [Tn+1 xn+1 = d1, …, Tn+k xn+k = dk]) => e is equivalent to a variable declaration of the form final id = (T1 a1, …, Tn an, [Tn+1 xn+1 = d1,…, Tn+k xn+k = dk])=> e.

A function literal of the form (T1 a1, …, Tn an, [Tn+1 xn+1 = d1 ,… ,Tn+k xn+k = dk])=> e is equivalent to a function literal of the form (T1 a1, …, Tn an, [Tn+1 xn+1 = d1,… Tn+k xn+k = dk]){ ereturn ;}.

It is a compile-time error to preface a function declaration with the built-in identifier static.

Formal Parameters

Every function declaration includes a formal parameter list, which consists of a list of required parameters, followed by any optional parameters. Optional parameters consist of a set of named parameters.

The following can be simplified to:
formalParameterList
: ‘(‘ normalFormalParameters (‘,’ optionalFormalParameters)? ‘)’
;
optionalFormalParameters

: restFormalParameter |

namedFormalParameters

;
| ‘(‘ namedFormalParameters ‘)’
| ‘(‘ normalFormalParameters normalFormalParameterTail? ‘)’
;

formalParameterList:
‘(‘ ‘)’
| ‘(‘ normalFormalParameters ( ‘,’ namedFormalParameters)? ‘)’
| ‘(‘ namedFormalParameters ‘)’
;

normalFormalParameters:
normalFormalParameter (‘,’ normalFormalParameter)*
;

namedFormalParameters:
‘[‘ defaultFormalParameter (‘,’ defaultFormalParameter)* ‘]’
;

Positional Formals

A positional formal parameter is a simple variable declaration.

normalFormalParameter:
functionSignature
| fieldFormalParameter
| simpleFormalParameter
;

simpleFormalParameter:
declaredIdentifier
| identifier
;

fieldFormalParameter:
finalVarOrType? this ‘.’ identifier
;

Named Optional Formals

Optional parameters may be specified and provided with default values.

defaultFormalParameter:
normalFormalParameter (‘=’ constantExpression)?
;

It is a compile-time error if the default value of a named parameter is not a compile-time constant.
If no default is explicitly specified for an optional parameter, but a default could legally be provided, an implicit default of null is provided.

There are situations (in abstract methods and interfaces) where optional parameters are allowed but an explicit default is illegal. In these cases, no implicit default is provided. This causes no difficulty, as any implementation of the method will provide defaults.

It is a compile-time error if the name of a named optional parameter begins with an ‘_’ character.

The need for this restriction is a direct consequence of the fact that naming and privacy are not orthogonal. If we allowed named parameters to begin with an underscore, they would be considered private and inaccessible to callers from outside the library where it was defined. If a method outside the library overrode a method with a private optional name, it would not be a subtype of the original method. The static checker would of course flag such situations, but the consequence would be that adding a private named formal would break clients outside the library in a way they could not easily correct.

Type of a Function

If a function does not declare a return type explicitly, its return type is Dynamic.
Let F be a function with required formal parameters T1 p1, …, Tn pn., return type T0 and named optional parameters Tn+1 pn+1, . . . , Tn+k pn+k. Then the type of F is (T1 , …, Tn, [pn+1:Tn+1, …, pn+k:Tn+k]) → T0.]

Classes

A class defines the form and behavior of a set of objects which are its instances.

classDefinition:
class identifier typeParameters? superclass? interfaces?
‘{‘ classMemberDefinition* ‘}’
;

classMemberDefinition:
declaration ‘;’
| methodSignature functionBody
;

methodSignature:
factoryConstructorSignature
| static functionSignature
| getterSignature
| setterSignature
| operatorSignature
| functionSignature initializers?
| namedConstructorSignature initializers?
;

declaration:
constantConstructorSignature (redirection | initializers)?
| functionSignature redirection
| namedConstructorSignature redirection
| abstract getterSignature
| abstract setterSignature
| abstract operatorSignature
| abstract functionSignature
| static final type? staticFinalDeclarationList
| static? initializedVariableDeclaration
;

staticFinalDeclarationList:
: staticFinalDeclaration (‘,’ staticFinalDeclaration)*
;

staticFinalDeclaration:
identifier ‘=’ constantExpression
;

A class has constructors, instance members and static members. The instance members of a class are its instance methods, getters, setters and instance variables. The static members of a class are its static methods, getters, setters and static variables.

Every class has a single superclass except class Object which has no superclass. A class may implement a number of interfaces by declaring them in its implements clause.

An abstract class is a class that is either explicitly declared with the abstract modifier, or a class that declares at least one abstract method.

The abstract modifier for classes is not yet implemented.

The interface of class C is an implicit interface that declares instance members that correspond to the instance members declared by C, and whose direct superinterfaces are the direct superinterfaces of C. When a class name appears as type or interface, that name denotes the interface of the class.

It is a compile-time error if a class declares two members of the same name, except that a getter and a setter may be declared with the same name provided both are instance members or both are static members.

What about a final instance variable and a setter? This case is illegal as well. If the setter is setting the variable, the variable should not be final.

It is a compile-time error if a class has two member variables with the same name. It is a compile-time error if a class has an instance method and a static member method with the same name.

It is a static warning if a class C declares an instance member named n and a static member named n is declared in a superclass of C.

Instance Methods

Instance methods are functions whose declarations are immediately contained within a class declaration and that are not declared static. The instance methods of a class C are those instance methods declared by C and the instance methods inherited by C from its superclass.

It is a compile-time error if an instance method m1 overrides an instance member m2 and m1 has a different number of required parameters than m2. It is a compile-time error if an instance method m1 overrides an instance member m2 and m1 does not declare all the named parameters declared by m2 in the same order.

It is a static warning if an instance method m1 overrides an instance method m2 and the type of m1 is not a subtype of the type of m2.

Abstract Methods

An abstract method declares an instance method without providing an implementation. The declaration of an abstract method is prefixed by the built in identifier abstract. It is a compile-time error to specify a body for an abstract method. It is a compile-time error if any default values are specified in the signature of an abstract method. This could all be enforced syntactically.

The abstract modifier for classes is not implemented. It is intended to be used in scenarios where an abstract class A inherits from another abstract class B. In such a situation, it may be that A itself does not declare any abstract methods. In the absence of an abstract modifier on the class, the class would be interpreted as a concrete class. However, we want different behavior for concrete classes and abstract classes. If A is intended to be abstract, we want the static checker to warn about any attempt to instantiate A, and we do not want the checker to complain about unimplemented methods in A. In contrast, if A is intended to be concrete, the checker should warn about all unimplemented methods, but allow clients to instantiate it freely.

Invoking an abstract method always results in a run-time error. This may be an instance of NoSuchMethodError or a subclass, such as AbstractMethodError.

These errors are ordinary objects and are therefore catchable.

Unless explicitly stated otherwise, all ordinary rules that apply to methods apply to abstract methods.

Operators

Operators are instance methods with special names.

operatorSignature:
returnType? operator operator formalParameterList
;

operator:
unaryOperator
| binaryOperator
| ‘[‘ ‘]’
| ‘[‘ ‘]’ ‘=’
| negate
;

unaryOperator:
negateOperator
;

binaryOperator:
multiplicativeOperator
| additiveOperator
| shiftOperator
| relationalOperator
| equalityOperator
| bitwiseOperator
;

prefixOperator:
‘-‘
| negateOperator
;

negateOperator:
‘!’
| ‘~’
;

An operator declaration is identified with built-in identifier operator.

The following names are allowed for user-defined operators: ==, <, >, <=, >=, -, +, /, ~/, *, %, |, ^, &, <<, >>, >>>, []=, [], ~, negate.

The built-in identifier negate is used to denote unary minus.

It is a compile-time error if the number of formal parameters of the user-declared operator []= is not 2. It is a compile time error if the number of formal parameters of a user-declared operator with one of the names: ==, <, >, <=, >=, -, +, /, ~/, *, %, |, ^, &, <<, >>, >>>, [] is not 1. It is a compile time error if the arity of a user-declared operator with one of the names: ~, negate is not 0.

It is a compile-time error to declare an optional named parameter in an operator.

Getters

Getters are functions that are used to retrieve the values of object properties.

getterSignature:
static? returnType? get identifier formalParameterList

If no return type is specified, the return type of the getter is Dynamic.

A getter definition that is prefixed with the static modifier defines a static getter. Otherwise, it defines an instance getter. The name of the getter is given by the identifier in the definition.

It is a compile-time error if a getter’s formal parameter list is not empty.

It is a compile-time error if a class has both a getter and a method with the same name. This restriction holds regardless of whether the getter is defined explicitly or implicitly, or whether the getter or the method are inherited or not.

This implies that a getter can never override a method, and a method can never override a getter or field.

It is a static warning if a getter m1 overrides a getter m2 and the type of m1 is not a subtype of the type of m2.

Setters

Setters are functions that are used to set the values of object properties.

setterSignature:
static? returnType? set identifier formalParameterList

If no return type is specified, the return type of the setter is Dynamic.

A setter definition that is prefixed with the static modifier defines a static setter. Otherwise, it defines an instance setter. The name of the setter is given by the identifier in the definition.

It is a compile-time error if a setter’s formal parameter list does not include exactly one required formal parameter p. We could enforce this via the grammar, but we’d have to specify the evaluation rules in that case.

It is a compile-time error if a class has both a setter and a method with the same name. This restriction holds regardless of whether the setter is defined explicitly or implicitly, or whether the setter or the method are inherited or not.

Hence, a setter can never override a method, and a method can never override a setter.

It is a static warning if a setter declares a return type other than void. It is a static warning if a setter m1 overrides a setter m2 and the type of m1 is not a subtype of the type of m2. It is a static warning if a class has a setter with argument type T and a getter of the same name with return type S, and T may not be assigned to S.

Instance Variables

Instance variables are variables whose declarations are immediately contained within a class declaration and that are not declared static. The instance variables of a class C are those instance variables declared by C and the instance variables inherited by C from its superclass.

If an instance variable declaration has one of the forms T v = e;, var v = e;, final T v = e; or final v = e; then the expression e must be a compile-time constant.

In Dart, all uninitialized variables have the value null, regardless of type. Numeric variables in particular must, therefore, be explicitly initialized; such variables will not be initialized to 0 by default. The form above is intended to ease the burden of such initialization.

An instance variable declaration of one of the forms T v = e;, var v = e;, final T v = e; or final v = e; always induces an implicit getter function with signature

T get v()

whose invocation evaluates to the value stored in v.
An instance variable declaration of one of the forms var v;, final v;, var v = e; or final v = e; always induces an implicit getter function with signature

get v()

whose invocation evaluates to the value stored in v.

Getters are introduced for all instance and static variables, regardless of whether they are final or not.

A non-final instance variable declaration of the form T v; or the form T v = e; always induces an implicit setter function with signature

void set v(T x)

whose execution sets the value of v to the incoming argument x.

A non-final instance variable declaration of the form var v; or the form var v = e; always induces an implicit setter function with signature

set v(x)

whose execution sets the value of v to the incoming argument x.

Constructors

A constructor is a special member that is used in instance creation expressions (instanceCreation) to produce objects. Constructors may be generative or they may be factories.

A constructor name always begins with the name of its immediately enclosing class or interface, and may optionally be followed by a dot and an identifier. The name of a non-factory constructor must be a constructor name.

Interfaces can have constructor Signatures (but not bodies). See the discussion of factories.

If no constructor is specified for a class C, it implicitly has a default constructor C() : super() {}.

Generative Constructors

A generative constructor consists of a constructor name, a constructor parameter list, an initializer list and an optional body.

constructorSignature:
identifier formalParameterList
| namedConstructorSignature
;

namedConstructorSignature:
identifier ‘.’ identifier formalParameterList
;

A constructor parameter list is a parenthesized, comma-separated list of formal constructor parameters. A formal constructor parameter is either a formal parameter or an initializing formal. An initializing formal has the form this.id. It is a compile-time error if id is not the name of an instance variable of the immediately enclosing class.

A fresh instance is an instance whose identity is distinct from any previously allocated instance of the class. A generative constructor always allocates a fresh instance of its immediately enclosing class. The above holds if the constructor is actually run, as it is by new. If a constructor c is referenced by const, c may not be run; instead, a canonical object may be looked up. See the section on instance creation.

If a generative constructor c is not a redirecting constructor and no body is provided, then c implicitly has an empty body {}.

Redirecting Constructors

A generative constructor may be redirecting, in which case its only action is to invoke another generative constructor. A redirecting constructor has no body; instead, it has a redirect clause that specifies which constructor the invocation is redirected to, and with what arguments.

redirection:
‘:’ this (‘.’ identifier)? arguments
;

Initializer Lists

An initializer list begins with a colon, and consists of a comma-separated list of individual initializers. There are two kinds of initializers.

  • A superinitializer specifies a superconstructor – that is, a specific constructor of the superclass. Execution of the superinitializer causes the initializer list of the superconstructor to be executed.
  • An instance variable initializer assigns a value to an individual instance variable.

initializers:
‘:’ superCallOrFieldInitializer (‘,’ superCallOrFieldInitializer)*
;

superCallOrFieldInitializer:
super arguments
| super ‘.’ identifier arguments
| fieldInitializer
;

fieldInitializer:
(this ‘.’)? identifier ‘=’ conditionalExpression
;

Let k be a generative constructor. Then k may include at most one superinitializer in its initializer list or a compile time error occurs. If no superinitializer is provided, an implicit superinitializer of the form super() is added at the end of k’s initializer list, unless the enclosing class is class Object. It is a compile time error if more than one initializer corresponding to a given instance variable appears in k’s list. It is a compile time error if k’s initializer list contains an initializer for a variable that is initialized by means of an initializing formal of k.

Each final instance variable f declared in the immediately enclosing class must have an initializer in k’s initializer list unless it has already been initialized by one of the following means:

  • Initialization at the declaration of f.
  • Initialization by means of an initializing formal of k.

or a compile-time error occurs. It is a compile-time error if k’s initializer list contains an initializer for a variable that is not an instance variable declared in the immediately surrounding class.

The initializer list may of course contain an initializer for any instance variable declared by the immediately surrounding class, even if it is not final.

It is a compile-time error if a generative constructor of class Object includes a superinitializer.

Execution of a generative constructor proceeds as follows:

First, a fresh instance i of the immediately enclosing class is allocated. Next, the instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text. For each such declaration d, if d has the form finalVarOrType v = e; then the instance variable v of i is bound to the value of e (which is necessarily a compile-time constant).
Next, any initializing formals declared in the constructor’s parameter list are executed in the order they appear in the program. Then, the constructor’s initializers are executed in the order they appear in the program.

We could observe the order by side effecting external routines called. So we need to specify the order.

After all the initializers have completed, the body of the constructor is executed in a scope where this is bound to i. Execution of the body begins with execution of the body of the superconstructor with respect to the bindings determined by the argument list of the superinitializer of k.

This process ensures that no uninitialized final field is ever seen by code. Note that this is not in scope on the right hand side of an initializer so no instance method can execute during initialization: an instance method cannot be directly invoked, nor can this be passed into any other code being invoked in the initializer.

Execution of an initializer of the form this.v = e proceeds as follows:

First, the expression e is evaluated to an object o. Then, the instance variable v of the object denoted by this is bound to o.

An initializer of the form v = e is equivalent to an initializer of the form this.v = e.

Execution of a superinitializer of the form super(a1, …, an, xn+1: an+1, …, xn+k: an+k) (respectively super.id(a1, …, an, xn+1: an+1, …, xn+k: an+k)) proceeds as follows:

First, the argument list (a1, …, an, xn+1: an+1, …, xn+k: an+k) is evaluated.
Let C be the class in which the superinitializer appears and let S be the superclass of C. If S is generic, let U1, ,.., Um be the actual type parameters passed to S in the superclass clause of C.

Then, the initializer list of the constructor S (respectively S.id) is executed with respect to the bindings that resulted from the evaluation of the argument list, with this bound to the current binding of this, and the type parameters (if any) of class S bound to the current binding of U1, ,.., Um.

It is a compile-time error if class S does not have a constructor named S (respectively S.id)

Factories

A factory is a static method prefaced by the built-in identifier factory.

factoryConstructorSignature:
factory qualified typeParameters? (‘.’ identifier)? formalParameterList
;

It is a static warning if the name of the method is not either:

  • A constructor name.
  • The name of a constructor of an interface that is in scope at the point where the factory is declared.

The return type of a factory whose signature is of the form factory M or the form factory M.id is M. The return type of a factory whose signature is of the form factory M <T1 extends B1, …, Tn extends Bn> or the form factory M <T1 extends B1, …, Tn extends Bn>.id is M <T1, …, Tn>.

It is a compile-time error if M is not the name of the immediately enclosing class or the name of an interface in the enclosing lexical scope. It is a compile-time error if the type M declares p type parameters where p != n.

In checked mode, it is a dynamic type error if a factory returns an object whose type is not a subtype of its actual return type.

It seems useless to allow a factory to return null. But it is more uniform to allow it, as the rules currently do.

Factories address classic weaknesses associated with constructors in other languages.
Factories can produce instances that are not freshly allocated: they can come from a cache. Likewise, factories can return instances of different classes.

Constant Constructors

A constant constructor may be used to create compile-time constant objects. A constant constructor is prefixed by the reserved word const. It is a compile-time error if a constant constructor has a body.

constantConstructorSignature:
const qualified formalParameterList
;

All the work of a constant constructor must be handled via its initializers.

It is a compile-time error if a constant constructor is declared by a class that has a non-final instance variable.
The above refers to both locally declared and inherited instance variables.
Any expression that appears within the initializer list of a constant constructor must be a potentially constant expression, or a compile-time error occurs.

A potentially constant expression is an expression e that would be a valid constant expression if all formal parameters of e’s immediately enclosing constant constructor were treated as compile-time constants that were guaranteed to evaluate to an integer, boolean or string value as required by their immediately enclosing superexpression.

The difference between a potentially constant expression and a compile-time constant expression deserves some explanation.

The key issue is whether one treats the formal parameters of a constructor as compile-time constants.

If a constant constructor is invoked from a constant object expression, the actual arguments will be required to be compile-time constants. Therefore, if we were assured that constant constructors were always invoked from constant object expressions, we could assume that the formal parameters of a constructor were compile-time constants.

However, constant constructors can also be invoked from ordinary instance creation expressions, and so the above assumption is not generally valid.

Nevertheless, the use of the formal parameters of a constant constructor within the constructor is of considerable utility. The concept of potentially constant expressions is introduced to facilitate limited use of such formal parameters. Specifically, we allow the usage of the formal parameters of a constant constructor for expressions that involve built-in operators, but not for constant objects, lists and maps. This allows for constructors such as:

class C {
final x; final y; final z;
const C(p, q): x = q, y = p + 100, z = p + q;
}

The assignment to x is allowed under the assumption that p is a compile-time constant (even though p is not, in general a compile-time constant). The assignment to y is similar, but raises additional questions. In this case, the superexpression of p is p + 100, and it requires that p be a numeric compile-time constant for the entire expression to be considered constant. The wording of the specification allows us to assume that p evaluates to an integer. A similar argument holds for p and q in the assignment to z.

However, the following constructors are disallowed:

class D {
final w;
const D.makeList(p): w = const [p]; // compile-time error
const D.makeMap(p): w = const {“help”: p}; // compile-time error
const D.makeC(p): w = const C(p, 12); // compile-time error
}

The problem is not that the assignments to w are not potentially constant; they are. However, all these run afoul of the rules for constant lists, maps and objects, all of which independently require their subexpressions to constant expressions.

All of the illegal constructors of D above could not be sensibly invoked via new, because an expression that must be constant cannot depend on a formal parameter, which may or may not be constant. In contrast, the legal examples make sense regardless of whether the constructor is invoked via const or via new.

Careful readers will of course worry about cases where the actual arguments to C() are constants, but are not of appropriate type. This is precluded by the following rule, combined with the rules for evaluating constant objects.

When invoked from a constant object expression, a constant constructor must throw an exception if any of its actual parameters would be a value that would cause one of the potentially constant expressions within it to not be a valid compile-time constant.

Static Methods

Static methods are functions whose declarations are immediately contained within a class declaration and that are declared static. The static methods of a class C are those static methods declared by C.

Inheritance of static methods has little utility in Dart. Static methods cannot be overridden. Any required static function can be obtained from its declaring library, and there is no need to bring it into scope via inheritance. Experience shows that developers are confused by the idea of inherited methods that are not instance methods.

Of course, the entire notion of static methods is debatable, but it is retained here because so many programmers are familiar with it. Dart static methods may be seen as functions of the enclosing library.

It is a static warning if a class has a static method with the same name as a static member of one of its superclasses.

This last restriction makes classes more brittle with respect to changes in the class hierarchy. It stems from a general observation that shadowing of names in the same scope is questionable and should elicit a warning.

There is no hiding of static methods, or of static variables.

Static Variables

Static variables are variables whose declarations are immediately contained within a class declaration and that are declared static. The static variables of a class C are those static variables declared by C.

A static variable declaration of one of the forms static T v;, static T v = e; or static final T v = e;always induces an implicit static getter function with signature

static T get v()

whose invocation evaluates to the value stored in v.

A static variable declaration of one of the forms static var v;, static var v = e; or static final v = e;always induces an implicit static getter function with signature

static get v()

whose invocation evaluates to the value stored in v.

A non-final static variable declaration of the form static T v; or the form static T v = e; always induces an implicit static setter function with signature

static void set v(T x)

whose execution sets the value of v to the incoming argument x.

A non-final static variable declaration of the form static var v; or the form static var v = e; always induces an implicit static setter function with signature

static set v(x)

whose execution sets the value of v to the incoming argument x.

It is a static warning if a class has a static variable with the same name as a static member of one of its superclasses.

Superclasses

The extends clause of a class C specifies its superclass. If no extends clause is specified, then either:

  • C is Object, which has no superclass. OR
  • The superclass of C is Object.

It is a compile-time error to specify an extends clause for class Object.

superclass:
extends type
;

It is a compile-time error if the extends clause of a class C includes a type expression that does not denote a class available in the lexical scope of C.

A class S is a superclass of a class C iff either:

  • S is the superclass of C, or
  • S is a superclass of a class S’ and S’ is a superclass of C.

It is a compile-time error if a class C is a superclass of itself.

Inheritance and Overriding

A class C inherits any instance members of its superclass that are not overridden by instance members declared in C.

A class may override instance members that would otherwise have been inherited from its superclass.

Let C be a class declared in library L with superclass S and let C declare an instance member m, and assume S declares an instance member m’ with the same name as m. Then m overrides m’ iff m is accessibleto L and one of the following holds:

  • m is an instance method.
  • m is a getter and m’ is a getter or a method.
  • m is a setter and m’ is a setter or a method.

Whether an override is legal or not is described elsewhere in this specification.

For example getters and setters may not legally override methods and vice versa.

It is nevertheless convenient to define the override relation between members in this way, so that we can concisely describe the illegal cases.

Note that instance variables do not participate in the override relation, but the getters and setters they induce do. Also, getters don’t override setters and vice versa. Finally, static members never override anything.

Superinterfaces

A class has a set of direct superinterfaces. This set includes the interface of its superclass and the interfaces specified in the the implements clause of the class.

interfaces:
implements typeList
;

It is a compile-time error if the implements clause of an class C includes a type expression that does not denote a class or interface available in the lexical scope of C.

In particular, one cannot inherit from a type variable.

It is a compile-time error if the implements clause of a class includes type Dynamic.
It is a compile-time error if a type T appears more than once in the implements clause of a class.

One might argue that it is harmless to repeat a type in this way, so why make it an error? The issue is not so much that the situation described in program source is erroneous, but that it is pointless. As such, it is an indication that the programmer may very well have meant to say something else – and that is a mistake that should be called to her or his attention. Nevertheless, we could simply issue a warning; and perhaps we should and will. That said, problems like these are local and easily corrected on the spot, so we feel justified in taking a harder line.

It is a compile-time error if the interface induced by a class C is a superinterface of itself.

A class does not inherit members from its superinterfaces. However, its implicit interface does.

dartgoogle.wordpress.com

< Prev – Google Dart Language Specification I

Next – Google Dart Language Specification III – Interfaces and expressions >

Next – Google Dart Language Specification IV – Statemets, scripts and types > 

:: Official Link Dartlang.org

2 thoughts on “Google Dart Language Specification II – Variables, Functions and Classes

  1. Pingback: Google Dart Language Specification III – Interfaces and expressions « Moises Belchin

  2. Pingback: Google Dart Language Specification « Moises Belchin

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s