Dart Language Specification
Dart Language Specification
Dart Language Specification
Version 1.2
The Dart Team
March 7, 2014
Contents
1 Notes 5
1.1 Licensing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Notation 5
3 Overview 7
3.1 Scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2 Privacy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.3 Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4 Errors and Warnings 10
5 Variables 11
5.1 Evaluation of Implicit Variable Getters . . . . . . . . . . . . . . . 14
6 Functions 15
6.1 Function Declarations . . . . . . . . . . . . . . . . . . . . . . . . 16
6.2 Formal Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.2.1 Required Formals . . . . . . . . . . . . . . . . . . . . . . . 17
6.2.2 Optional Formals . . . . . . . . . . . . . . . . . . . . . . . 18
6.3 Type of a Function . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.4 External Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7 Classes 19
7.1 Instance Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.1 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
7.2 Getters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.3 Setters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.4 Abstract Instance Members . . . . . . . . . . . . . . . . . . . . . 24
7.5 Instance Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7.6 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1
7.6.1 Generative Constructors . . . . . . . . . . . . . . . . . . . 26
7.6.2 Factories . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
7.6.3 Constant Constructors . . . . . . . . . . . . . . . . . . . . 31
7.7 Static Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
7.8 Static Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
7.9 Superclasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
7.9.1 Inheritance and Overriding . . . . . . . . . . . . . . . . . 34
7.10 Superinterfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
8 Interfaces 37
8.1 Superinterfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
8.1.1 Inheritance and Overriding . . . . . . . . . . . . . . . . . 38
9 Mixins 39
9.1 Mixin Application . . . . . . . . . . . . . . . . . . . . . . . . . . 40
9.2 Mixin Composition . . . . . . . . . . . . . . . . . . . . . . . . . . 41
10 Generics 41
11 Metadata 42
12 Expressions 43
12.0.1 Object Identity . . . . . . . . . . . . . . . . . . . . . . . . 44
12.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
12.2 Null . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
12.3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
12.4 Booleans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
12.4.1 Boolean Conversion . . . . . . . . . . . . . . . . . . . . . 49
12.5 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
12.5.1 String Interpolation . . . . . . . . . . . . . . . . . . . . . 53
12.6 Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
12.7 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
12.8 Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
12.9 Throw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.10 Function Expressions . . . . . . . . . . . . . . . . . . . . . . . . 58
12.11 This . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.12 Instance Creation . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.12.1 New . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.12.2 Const . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
12.13 Spawning an Isolate . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.14 Property Extraction . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.15 Function Invocation . . . . . . . . . . . . . . . . . . . . . . . . . 65
12.15.1 Actual Argument List Evaluation . . . . . . . . . . . . . 65
12.15.2 Binding Actuals to Formals . . . . . . . . . . . . . . . . . 66
12.15.3 Unqualied Invocation . . . . . . . . . . . . . . . . . . . 66
12.15.4 Function Expression Invocation . . . . . . . . . . . . . . 67
2
12.16 Method Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . 67
12.16.1Ordinary Invocation . . . . . . . . . . . . . . . . . . . . . 67
12.16.2Cascaded Invocations . . . . . . . . . . . . . . . . . . . . 69
12.16.3Static Invocation . . . . . . . . . . . . . . . . . . . . . . . 69
12.16.4Super Invocation . . . . . . . . . . . . . . . . . . . . . . . 70
12.16.5Sending Messages . . . . . . . . . . . . . . . . . . . . . . . 71
12.17 Getter and Setter Lookup . . . . . . . . . . . . . . . . . . . . . . 71
12.18 Getter Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . 72
12.19 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
12.19.1Compound Assignment . . . . . . . . . . . . . . . . . . . 75
12.20 Conditional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
12.21 Logical Boolean Expressions . . . . . . . . . . . . . . . . . . . . 76
12.22 Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.23 Relational Expressions . . . . . . . . . . . . . . . . . . . . . . . 78
12.24 Bitwise Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 78
12.25 Shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
12.26 Additive Expressions . . . . . . . . . . . . . . . . . . . . . . . . 80
12.27 Multiplicative Expressions . . . . . . . . . . . . . . . . . . . . . 80
12.28 Unary Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . 81
12.29 Postx Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 82
12.30 Assignable Expressions . . . . . . . . . . . . . . . . . . . . . . . 83
12.31 Identier Reference . . . . . . . . . . . . . . . . . . . . . . . . . 84
12.32 Type Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
12.33 Type Cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
13 Statements 88
13.1 Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.2 Expression Statements . . . . . . . . . . . . . . . . . . . . . . . . 89
13.3 Local Variable Declaration . . . . . . . . . . . . . . . . . . . . . . 89
13.4 Local Function Declaration . . . . . . . . . . . . . . . . . . . . . 90
13.5 If . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
13.6 For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
13.6.1 For Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
13.6.2 For-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
13.7 While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
13.8 Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.9 Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.10 Rethrow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
13.11 Try . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
13.12 Return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
13.13 Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
13.14 Break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
13.15 Continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
13.16 Assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3
14 Libraries and Scripts 103
14.1 Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
14.2 Exports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
14.3 Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
14.4 Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
14.5 URIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
15 Types 110
15.1 Static Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
15.1.1 Type Promotion . . . . . . . . . . . . . . . . . . . . . . . 112
15.2 Dynamic Type System . . . . . . . . . . . . . . . . . . . . . . . . 112
15.3 Type Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . 113
15.3.1 Typedef . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
15.4 Interface Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
15.5 Function Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
15.6 Type dynamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
15.7 Type Void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
15.8 Parameterized Types . . . . . . . . . . . . . . . . . . . . . . . . . 118
15.8.1 Actual Type of Declaration . . . . . . . . . . . . . . . . . 119
15.8.2 Least Upper Bounds . . . . . . . . . . . . . . . . . . . . . 119
16 Reference 120
16.1 Lexical Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
16.1.1 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . 120
16.1.2 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
16.2 Operator Precedence . . . . . . . . . . . . . . . . . . . . . . . . . 122
4
Dart Programming Language Specication 5
1 Notes
1.1 Licensing
Except as otherwise noted at https://developers.google.com/site-policies, the
content of this document is licensed under the Creative Commons Attribution
3.0 License available at:
http://creativecommons.org/licenses/by/3.0/
and code samples are licensed under the license available at
https://code.google.com/p/dart/source/browse/trunk/dart/LICENSE.
2 Notation
We distinguish between normative and non-normative text. Normative text
denes the rules of Dart. It is given in this font. At this time, non-normative
text includes:
Rationale Discussion of the motivation for language design decisions appears in ital-
ics. Distinguishing normative from non-normative helps clarify what part
of the text is binding and what part is merely expository.
Commentary Comments such as The careful reader will have noticed that the name Dart
has four characters serve to illustrate or clarify the specication, but are
redundant with the normative text. The dierence between commentary
and rationale can be subtle. Commentary is more general than rationale,
and may include illustrative examples or clarications.
Open questions (in this font). Open questions are points that are unsettled in the mind
of the author(s) of the specication; expect them (the questions, not the
authors; precision is important in a specication) to be eliminated in the
nal specication. Should the text at the end of the previous bullet
be rationale or commentary?
Reserved words and built-in identiers (12.31) appear in bold.
Examples would be switch or class.
Grammar productions are given in a common variant of EBNF. The left
hand side of a production ends with a colon. On the right hand side, alterna-
tion is represented by vertical bars, and sequencing by spacing. As in PEGs,
alternation gives priority to the left. Optional elements of a production are suf-
xed by a question mark like so: anElephant?. Appending a star to an element
of a production means it may be repeated zero or more times. Appending a plus
sign to a production means it occurs one or more times. Parentheses are used
for grouping. Negation is represented by prexing an element of a production
with a tilde. Negation is similar to the not combinator of PEGs, but it consumes
input if it matches. In the context of a lexical production it consumes a single
character if there is one; otherwise, a single token if there is one.
An example would be:
Dart Programming Language Specication 6
AProduction:
AnAlternative |
AnotherAlternative |
OneThing After Another |
ZeroOrMoreThings* |
OneOrMoreThings+ |
AnOptionalThing? |
(Some Grouped Things) |
NotAThing |
A LEXICAL THING
;
Both syntactic and lexical productions are represented this way. Lexical
productions are distinguished by their names. The names of lexical productions
consist exclusively of upper case characters and underscores. As always, within
grammatical productions, whitespace and comments between elements of the
production are implicitly ignored unless stated otherwise. Punctuation tokens
appear in quotes.
Productions are embedded, as much as possible, in the discussion of the
constructs they represent.
A list x
1
, . . . , x
n
denotes any list of n elements of the form x
i
, 1 i n.
Note that n may be zero, in which case the list is empty. We use such lists
extensively throughout this specication.
The notation [x
1
, . . . , x
n
/y
1
, . . . , y
n
]E denotes a copy of E in which all oc-
currences of y
i
, 1 i n have been replaced with x
i
.
We sometimes abuse list or map literal syntax, writing [o
1
, . . . , o
n
] (respec-
tively {k
1
: o
1
, . . . , k
n
: o
n
}) where the o
i
and k
i
may be objects rather than
expressions. The intent is to denote a list (respectively map) object whose
elements are the o
i
(respectively, whose keys are the k
i
and values are the o
i
).
The specications of operators often involve statements such as x op y is
equivalent to the method invocation x.op(y). Such specications should be
understood as a shorthand for:
x op y is equivalent to the method invocation x.op
denoted
by type (respectively, type.identifier) to be called with the actual arguments
passed to k, and returns the result of k
.
It is a compile-time error if k explicitly species a default value for an op-
tional parameter. Default values specied in k would be ignored, since it is the
actual parameters that are passed to k
. At
rst glance, one might think that ordinary factory constructors could simply
create instances of other classes and return them, and that redirecting factories
are unnecessary. However, redirecting factories have several advantages:
An abstract class may provide a constant constructor that utilizes the con-
stant constructor of another class.
A redirecting factory constructors avoids the need for forwarders to repeat
the default values for formal parameters in their signatures.
It is a compile-time error if k is prexed with the const modier but k
is
not a constant constructor (7.6.3).
It is a static warning if the function type of k
and S
is a superclass of C.
It is a compile-time error if a class C is a superclass of itself.
7.9.1 Inheritance and Overriding
Let C be a class, let A be a superclass of C, and let S
1
. . . S
k
be superclasses
of C that are also subclasses of A. C inherits all accessible instance members
of A that have not been overridden by a declaration in C or in at least one of
S
1
. . . S
k
.
It would be more attractive to give a purely local denition of inheritance,
that depended only on the members of the direct superclass S. However, a class
C can inherit a member m that is not a member of its superclass S. This can
occur when the member m is private to the library L
1
of C, whereas S comes
from a dierent library L
2
, but the superclass chain of S includes a class declared
in L
1
.
A class may override instance members that would otherwise have been
inherited from its superclass.
Let C = S
0
be a class declared in library L, and let {S
1
. . . S
k
} be the set
of all superclasses of C, where S
i
is the superclass of S
i1
for i 1..k. Let C
declare a member m, and let m
be a member of S
j
, j 1..k, that has the same
name as m, such that m
if m
is not
already overridden by a member of at least one of S
1
. . . S
j1
and neither m nor
m
are elds.
Fields never override each other. The getters and setters induced by elds do.
Again, a local denition of overriding would be preferable, but fails to account
for library privacy.
Whether an override is legal or not is described elsewhere in this specication
(see 7.1, 7.2 and 7.3).
For example getters may not legally override methods and vice versa. Setters
never override methods or getters, and vice versa, because their names always dier.
It is nevertheless convenient to dene 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 dont override setters and vice
versa. Finally, static members never override anything.
It is a static warning if a non-abstract class inherits an abstract method.
Dart Programming Language Specication 35
For convenience, here is a summary of the relevant rules. Remember that this
is not normative. The controlling language is in the relevant sections of the speci-
cation.
1. There is only one namespace for getters, setters, methods and constructors
(3.1). A eld f introduces a getter f and a non-nal eld f also introduces a
setter f = (7.5, 7.8). When we speak of members here, we mean accessible
elds, getters, setters and methods (7).
2. You cannot have two members with the same name in the same class - be
they declared or inherited (3.1, 7).
3. Static members are never inherited.
4. It is a warning if you have an static member named m in your class or any
superclass (even though it is not inherited) and an instance member of the
same name (7.1, 7.2, 7.3).
5. It is a warning if you have a static setter v =, and an instance member v
(7.3).
6. It is a warning if you have a static getter v and an instance setter v = (7.2).
7. If you dene an instance member named m, and your superclass has an
instance member of the same name, they override each other. This may or
may not be legal.
8. If two members override each other, it is a static warning if their type sig-
natures are not assignable to each other (7.1, 7.2, 7.3) (and since these are
function types, this means the same as subtypes of each other).
9. If two members override each other, it is a static warning if the overriding
member has more required parameters than the overridden one (7.1).
10. If two members override each other, it is a static warning if the overriding
member has fewer positional parameters than the the overridden one (7.1).
11. If two members override each other, it is a static warning if the overriding
member does not have all the named parameters that the the overridden one
has (7.1).
12. Setters, getters and operators never have optional parameters of any kind; its
a compile-time error (7.1.1, 7.2, 7.3).
13. It is a compile-time error if a member has the same name as its enclosing
class (7).
14. A class has an implicit interface (7).
15. Superinterface members are not inherited by a class, but are inherited by its
implicit interface. Interfaces have their own inheritance rules (8.1.1).
Dart Programming Language Specication 36
16. A member is abstract if it has no body and is not labeled external (7.4, 6.4).
17. A class is abstract i it is explicitly labeled abstract.
18. It is a static warning a concrete class has an abstract member (declared or
inherited).
19. It is a static warning and a dynamic error to call a non-factory constructor of
an abstract class (12.12.1).
20. If a class denes an instance member named m, and any of its superinterfaces
have a member named m, the interface of the class overrides m.
21. An interface inherits all members of its superinterfaces that are not overridden
and not members of multiple superinterfaces.
22. If multiple superinterfaces of an interface dene a member with the same
name m, then at most one member is inherited. That member (if it exists) is
the one whose type is a subtype of all the others. If there is no such member,
then:
A static warning is given.
If possible the interface gets a member named m that has the minimum
number of required parameters among all the members in the superin-
terfaces, the maximal number of positionals, and the superset of named
parameters. The types of these are all dynamic. If this is impossible
then no member m appears in the interface.
(8.1.1)
23. Rule 8 applies to interfaces as well as classes (8.1.1).
24. It is a static warning if a concrete class does not have an implementation for a
method in any of its superinterfaces unless it declares its own noSuchMethod
method (7.10).
25. The identier of a named constructor cannot be the same as the name of a
member declared (as opposed to inherited) in the same class (7.6).
7.10 Superinterfaces
A class has a set of direct superinterfaces. This set includes the interface of
its superclass and the interfaces specied in the the implements clause of the
class.
interfaces:
implements typeList
;
Dart Programming Language Specication 37
It is a compile-time error if the implements clause of a class C species a
type variable as a superinterface. It is a compile-time error if the implements
clause of a class C species a malformed type as a superinterface It is a compile-
time error if the implements clause of a class C species type dynamic as a
superinterface. It is a compile-time error if the implements clause of a class
C species a type T as a superinterface more than once. It is a compile-time
error if the superclass of a class C is specied as a superinterface of C.
One might argue that it is harmless to repeat a type in the superinterface list,
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 justied in taking
a harder line.
It is a compile-time error if the interface of a class C is a superinterface of
itself.
Let C be a concrete class that does not declare its own noSuchMethod()
method. It is a static warning if the implicit interface of C includes an instance
member m of type F and C does not declare or inherit a corresponding non-
abstract instance member m of type F
such that F
<: F.
A class does not inherit members from its superinterfaces. However, its implicit
interface does.
We choose to issue these warnings only for concrete classes; an abstract class
might legitimately be designed with the expectation that concrete subclasses will
implement part of the interface. We also disable these warnings if a noSuch-
Method() declaration is present. In such cases, the supported interface is going
to be implemented via noSuchMethod() and no actual declarations of the imple-
mented interfaces members are needed. This allows proxy classes for specic
types to be implemented without provoking type warnings.
In addition, it may be useful to suppress these warnings if noSuchMethod is
inherited, However, this may suppress meaningful warnings and so we choose
not to do so. If one does want to suppress the warnings in a subclass, one can
dene a simple implementation of noSuchMethod in the subclass:
noSuchMethod(inv) => super.noSuchMethod(inv);
It is a static warning if the implicit interface of a class C includes an instance
member mof type F and C declares or inherits a corresponding instance member
m of type F
if F
is not a subtype of F.
However, if a class does explicitly declare a member that conicts with its
superinterface, this always yields a static warning.
8 Interfaces
An interface denes how one may interact with an object. An interface has
methods, getters and setters and a set of superinterfaces.
Dart Programming Language Specication 38
8.1 Superinterfaces
An interface has a set of direct superinterfaces.
An interface J is a superinterface of an interface I i either J is a direct
superinterface of I or J is a superinterface of a direct superinterface of I.
8.1.1 Inheritance and Overriding
Let J be an interface and K be a library. We dene inherited(J, K) to be the
set of members m such that all of the following hold:
m is accessible to K and
A is a direct superinterface of J and either
A declares a member m or
m is a member of inherited(A, K).
m is not overridden by J.
Furthermore, we dene overrides(J, K) to be the set of members m
such
that all of the following hold:
J is the implicit interface of a class C.
C declares a member m.
m
is accessible to K.
A is a direct superinterface of J and either
A declares a member m
or
m
if m
overrides(I, L).
All the static warnings pertaining to the overriding of instance members
given in section 7 above hold for overriding between interfaces as well.
It is a static warning if m is a method and m
is a getter, or if m is a getter
and m
is a method.
However, if the above rules would cause multiple members m
1
, . . . , m
k
with
the same name n to be inherited (because identically named members existed
in several superinterfaces) then at most one member is inherited.
If some but not all of the m
i
, 1 i k are getters none of the m
i
are
inherited, and a static warning is issued.
Otherwise, if the static types T
1
, . . . , T
k
of the members m
1
, . . . , m
k
are not
identical, then there must be a member m
x
such that T
x
<: T
i
, 1 x k for
all i 1..k, or a static type warning occurs. The member that is inherited is
m
x
, if it exists; otherwise:
Dart Programming Language Specication 39
Let numberOfPositionals(f) denote the number of positional parame-
ters of a function f, and let numberOfRequiredParams(f) denote the
number of required parameters of a function f. Furthermore, let s denote
the set of all named parameters of the m
1
, . . . , m
k
. Then let
h = max(numberOfPositionals(m
i
)),
r = min(numberOfRequiredParams(m
i
)), i 1..k.
If r h then I has a method named n, with r required parameters of type
dynamic, h positional parameters of type dynamic, named parameters
s of type dynamic and return type dynamic.
Otherwise none of the members m
1
, . . . , m
k
is inherited.
The only situation where the runtime would be concerned with this would be
during reection, if a mirror attempted to obtain the signature of an interface
member.
The current solution is a tad complex, but is robust in the face of type an-
notation changes. Alternatives: (a) No member is inherited in case of conict.
(b) The rst m is selected (based on order of superinterface list) (c) Inherited
member chosen at random.
(a) means that the presence of an inherited member of an interface varies
depending on type signatures. (b) is sensitive to irrelevant details of the decla-
ration and (c) is liable to give unpredictable results between implementations or
even between dierent compilation sessions.
9 Mixins
A mixin describes the dierence between a class and its superclass. A mixin is
always derived from an existing class declaration.
It is a compile-time error if a declared or derived mixin refers to super.
It is a compile-time error if a declared or derived mixin explicitly declares a
constructor. It is a compile-time error if a mixin is derived from a class whose
superclass is not Object.
These restrictions are temporary. We expect to remove them in later versions
of Dart.
The restriction on the use of super avoids the problem of rebinding super
when the mixin is bound to dierence superclasses.
The restriction on constructors simplies the construction of mixin applica-
tions because the process of creating instances is simpler.
The restriction on the superclass means that the type of a class from which
a mixin is derived is always implemented by any class that mixes it in. This
allows us to defer the question of whether and how to express the type of the
mixin independently of its superclass and super interface types.
Reasonable answers exist for all these issues, but their implementation is
non-trivial.
Dart Programming Language Specication 40
9.1 Mixin Application
A mixin may be applied to a superclass, yielding a new class. Mixin application
occurs when a mixin is mixed into a class declaration via its with clause. The
mixin application may be used to extend a class per section (7); alternately, a
class may be dened as a mixin application as described in this section.
mixinApplicationClass:
identier typeParameters? = mixinApplication ;
;
mixinApplication:
type mixins interfaces?
;
A mixin application of the form S with M; denes a class C with superclass
S.
A mixin application of the form S with M
1
, . . . , M
k
; denes a class C whose
superclass is the application of the mixin composition (9.2) M
k1
. . . M
1
to
S.
In both cases above, C declares the same instance members as M (respec-
tively, M
k
). If any of the instance elds of M (respectively, M
k
) have initializers,
they are executed in the scope of M (respectively, M
k
) to initialize the corre-
sponding elds of C.
For each generative constructor named q
i
(T
i1
a
i1
, . . . , T
iki
a
iki
), i 1..n of
S, C has an implicitly declared constructor named q
i
= [C/S]q
i
of the form
q
i
(a
i1
, . . . , a
iki
) : super(a
i1
, . . . , a
iki
);.
If the mixin application declares support for interfaces, the resulting class
implements those interfaces.
It is a compile-time error if S is a malformed type. It is a compile-time error
if M (respectively, any of M
1
, . . . , M
k
) is a malformed type. It is a compile time
error if a well formed mixin cannot be derived from M (respectively, from each
of M
1
, . . . , M
k
).
Let K be a class declaration with the same constructors, superclass and inter-
faces as C, and the instance members declared by M (respectively M
1
, . . . , M
k
).
It is a static warning if the declaration of K would cause a static warning. It is
a compile-time error if the declaration of K would cause a compile-time error.
If, for example, M declares an instance member im whose type is at odds with
the type of a member of the same name in S, this will result in a static warning
just as if we had dened K by means of an ordinary class declaration extending S,
with a body that included im.
The eect of a class denition of the form class C = M; or the form class
C < T
1
, . . . , T
n
> = M; in library L is to introduce the name C into the scope
of L, bound to the class (7) dened by the mixin application M. The name
of the class is also set to C. I the class is prexed by the built-in identier
abstract, the class being dened is an abstract class.
Dart Programming Language Specication 41
9.2 Mixin Composition
Dart does not directly support mixin composition, but the concept is useful when
dening how the superclass of a class with a mixin clause is created.
The composition of two mixins, M
1
< T
1
. . . T
k
M
1
>and M
2
< U
1
. . . U
k
M
2
>,
written M
1
< T
1
. . . T
k
M
1
> M
2
< U
1
. . . U
k
M
2
> denes an anonymous mixin
such that for any class S < V
1
. . . V
k
S
>, the application of
M
1
< T
1
. . . T
k
M
1
> M
2
< U
1
. . . U
k
M
2
>
to S < V
1
. . . V
k
S
> is equivalent to
abstract class Id
1
< T
1
. . . T
k
M
1
, U
1
. . . U
k
M
2
, V
1
. . . V
k
S
> =
Id
2
< U
1
. . . U
k
M
2
, V
1
. . . V
k
S
> with M
1
< T
1
. . . T
k
M
1
>;
where Id
2
denotes
abstract class Id
2
< U
1
. . . U
k
M
2
, V
1
. . . V
k
S
> =
S < V
1
. . . V
k
S
> with M
2
< U
1
. . . U
k
M
2
>;
and Id
1
and Id
2
are unique identiers that do not exist anywhere in the
program.
The classes produced by mixin composition are regarded as abstract because
they cannot be instantiated independently. They are only introduced as anony-
mous superclasses of ordinary class declarations and mixin applications. Conse-
quently, no warning is given if a mixin composition includes abstract members,
or incompletely implements an interface.
Mixin composition is associative.
Note that any subset of M
1
, M
2
and S may or may not be generic. For any
non-generic declaration, the corresponding type parameters may be elided, and if no
type parameters remain in the derived declarations Id
1
and/or Id
2
then the those
declarations need not be generic either.
10 Generics
A class declaration (7) or type alias (15.3.1) G may be generic, that is, G may
have formal type parameters declared. A generic declaration induces a family of
declarations, one for each set of actual type parameters provided in the program.
typeParameter:
metadata identier (extends type)?
;
typeParameters:
< typeParameter (, typeParameter)* >
;
A type parameter T may be suxed with an extends clause that species
the upper bound for T. If no extends clause is present, the upper bound is
Object. It is a static type warning if a type parameter is a supertype of its
upper bound. The bounds of type variables are a form of type annotation and
have no eect on execution in production mode.
Dart Programming Language Specication 42
The type parameters of a generic G are in scope in the bounds of all of the
type parameters of G. The type parameters of a generic class declaration G are
also in scope in the extends and implements clauses of G (if these exist) and
in the body of G. However, a type parameter is considered to be a malformed
type when referenced by a static member.
The restriction is necessary since a type variable has no meaning in the
context of a static member, because statics are shared among all instantiations
of a generic. However, a type variable may be referenced from an instance
initializer, even though this is not available.
Because type parameters are in scope in their bounds, we support F-bounded
quantication (if you dont know what that is, dont ask). This enables typechecking
code such as:
interface Ordered<T> {
operator > (T x);
}
class Sorter<T extends Ordered<T>> {
sort(List<T> l) ... l[n] < l[n+1] ...
}
Even where type parameters are in scope there are numerous restrictions at this
time:
A type parameter cannot be used to name a constructor in an instance creation
expression (12.12).
A type parameter cannot be used as a superclass or superinterface (7.9, 7.10,
8.1).
The normative versions of these are given in the appropriate sections of this
specication. Some of these restrictions may be lifted in the future.
11 Metadata
Dart supports metadata which is used to attach user dened annotations to
program structures.
metadata:
(@ qualied (. identier)? (arguments)?)*
;
Metadata consists of a series of annotations, each of which begin with the
character @, followed by a constant expression that starts with an identier. It
is a compile time error if the expression is not one of the following:
A reference to a compile-time constant variable.
A call to a constant constructor.
Dart Programming Language Specication 43
Metadata is associated with the abstract syntax tree of the program con-
struct p that immediately follows the metadata, assuming p is not itself meta-
data or a comment. Metadata can be retrieved at runtime via a reective call,
provided the annotated program construct p is accessible via reection.
Obviously, metadata can also be retrieved statically by parsing the program and
evaluating the constants via a suitable interpreter. In fact many if not most uses of
metadata are entirely static.
It is important that no runtime overhead be incurred by the introduction of
metadata that is not actually used. Because metadata only involves constants,
the time at which it is computed is irrelevant so that implementations may skip
the metadata during ordinary parsing and execution and evaluate it lazily.
It is possible to associate metadata with constructs that may not be accessible
via reection, such as local variables (though it is conceivable that in the future,
richer reective libraries might provide access to these as well). This is not as useless
as it might seem. As noted above, the data can be retrieved statically if source
code is available.
Metadata can appear before a library, part header, class, typedef, type pa-
rameter, constructor, factory, function, eld, parameter, or variable declaration
and before an import, export or part directive.
The constant expression given in an annotation is type checked and evaluated
in the scope surrounding the declaration being annotated.
12 Expressions
An expression is a fragment of Dart code that can be evaluated at run time to
yield a value, which is always an object. Every expression has an associated
static type (15.1). Every value has an associated dynamic type (15.2).
expression:
assignableExpression assignmentOperator expression |
conditionalExpression cascadeSection* |
throwExpression
;
expressionWithoutCascade:
assignableExpression assignmentOperator expressionWithoutCas-
cade |
conditionalExpression |
throwExpressionWithoutCascade
;
expressionList:
expression (, expression)*
;
Dart Programming Language Specication 44
primary:
thisExpression |
super assignableSelector |
functionExpression |
literal |
identier |
newExpression |
constObjectExpression |
( expression )
;
An expression e may always be enclosed in parentheses, but this never has
any semantic eect on e.
Sadly, it may have an eect on the surrounding expression. Given a class C
with static method m => 42, C.m() returns 42, but (C).m() produces a NoSuch-
MethodError. This anomaly can be corrected by ensuring that every instance of
Type has instance members corresponding to its static members. This issue may
be addressed in future versions of Dart .
12.0.1 Object Identity
The predened Dart function identical() is dened such that identical(c
1
, c
2
) i:
c
1
evaluates to either null or an instance of bool and c
1
== c
2
, OR
c
1
and c
2
are instances of int and c
1
== c
2
, OR
c
1
and c
2
are constant strings and c
1
== c
2
, OR
c
1
and c
2
are instances of double and one of the following holds:
c
1
and c
2
are non-zero and c
1
== c
2
.
Both c
1
and c
2
are +0.0.
Both c
1
and c
2
are 0.0.
Both c
1
and c
2
represent a NaN value.
OR
c
1
and c
2
are constant lists that are dened to be identical in the speci-
cation of literal list expressions (12.7), OR
c
1
and c
2
are constant maps that are dened to be identical in the speci-
cation of literal map expressions (12.8), OR
c
1
and c
2
are constant objects of the same class C and each member eld
of c
1
is identical to the corresponding eld of c
2
. OR
c
1
and c
2
are the same object.
Dart Programming Language Specication 45
The denition of identity for doubles diers from that of equality in that a NaN
is equal to itself, and that negative and positive zero are distinct.
The denition of equality for doubles is dictated by the IEEE 754 standard,
which posits that NaNs do not obey the law of reexivity. Given that hardware
implements these rules, it is necessary to support them for reasons of eciency.
The denition of identity is not constrained in the same way. Instead, it
assumes that bit-identical doubles are identical.
The rules for identity make it impossible for a Dart programmer to observe
whether a boolean or numerical value is boxed or unboxed.
12.1 Constants
A constant expression is an expression whose value can never change, and that
can be evaluated entirely at compile time.
A constant expression is one of the following:
A literal number (12.3).
A literal boolean (12.4).
A literal string (12.5) where any interpolated expression (12.5.1) is a
compile-time constant that evaluates to a numeric, string or boolean value
or to null. It would be tempting to allow string interpolation where the in-
terpolated value is any compile-time constant. However, this would require
running the toString() method for constant objects, which could contain ar-
bitrary code.
A literal symbol (12.6).
null (12.2).
A qualied reference to a static constant variable (5). For example, If class
C declares a constant static variable v, C.v is a constant. The same is true if
C is accessed via a prex p; p.C.v is a constant.
An identier expression that denotes a constant variable.
A simple or qualied identier denoting a class or a type alias. For example,
if C is a class or typedef C is a constant, and if C is imported with a prex p,
p.C is a constant.
A constant constructor invocation (12.12.2).
A constant list literal (12.7).
A constant map literal (12.8).
A simple or qualied identier denoting a top-level function (6) or a static
method (7.7).
A parenthesized expression (e) where e is a constant expression.
Dart Programming Language Specication 46
An expression of the form identical(e
1
, e
2
) where e
1
and e
2
are constant ex-
pressions and identical() is statically bound to the predened dart function
identical() discussed above (12.0.1).
An expression of one of the forms e
1
== e
2
or e
1
!= e
2
where e
1
and
e
2
are constant expressions that evaluate to a numeric, string or boolean
value or to null.
An expression of one of the forms !e, e
1
&& e
2
or e
1
||e
2
, where e, e
1
and
e
2
are constant expressions that evaluate to a boolean value.
An expression of one of the forms e, e
1
e
2
, e
1
& e
2
, e
1
|e
2
, e
1
>> e
2
or
e
1
<< e
2
, where e, e
1
and e
2
are constant expressions that evaluate to an
integer value or to null.
An expression of one of the forms e, e
1
+e
2
, e
1
- e
2
, e
1
* e
2
, e
1
/ e
2
, e
1
/ e
2
, e
1
> e
2
, e
1
< e
2
, e
1
>= e
2
, e
1
<= e
2
or e
1
% e
2
, where e, e
1
and
e
2
are constant expressions that evaluate to a numeric value or to null.
An expression of the form e
1
?e
2
:e3 where where e
1
, e
2
and e
3
are constant
expressions and e
1
evaluates to a boolean value.
It is a compile-time error if an expression is required to be a constant ex-
pression but its evaluation would raise an exception.
Note that there is no requirement that every constant expression evaluate cor-
rectly. Only when a constant expression is required (e.g., to initialize a constant
variable, or as a default value of a formal parameter, or as metadata) do we insist
that a constant expression actually be evaluated successfully at compile time.
The above is not dependent on program control-ow. The mere presence of a
required compile time constant whose evaluation would fail within a program is an
error. This also holds recursively: since compound constants are composed out of
constants, if any subpart of a constant would raise an exception when evaluated,
that is an error.
On the other hand, since implementations are free to compile code late, some
compile-time errors may manifest quite late.
const x = 1/0;
nal y = 1/0;
class K {
m1() {
var z = false;
if (z) {return x; }
else { return 2;}
}
m2() {
if (true) {return y; }
else { return 3;}
}
}
Dart Programming Language Specication 47
An implementation is free to immediately issue a compilation error for x, but it
is not required to do so. It could defer errors if it does not immediately compile
the declarations that reference x. For example, it could delay giving a compilation
error about the method m1 until the rst invocation of m1. However, it could not
choose to execute m1, see that the branch that refers to x is not taken and return
2 successfully.
The situation with respect to an invocation m2 is dierent. Because y is not a
compile-time constant (even though its value is), one need not give a compile-time
error upon compiling m2. An implementation may run the code, which will cause
the getter for y to be invoked. At that point, the initialization of y must take place,
which requires the initializer to be compiled, which will cause a compilation error.
The treatment of null merits some discussion. Consider null + 2. This
expression always causes an error. We could have chosen not to treat it as a
constant expression (and in general, not to allow null as a subexpression of nu-
meric or boolean constant expressions). There are two arguments for including
it:
1. It is constant. We can evaluate it at compile-time.
2. It seems more useful to give the error stemming from the evaluation ex-
plicitly.
It is a compile-time error if the value of a compile-time constant expression
depends on itself.
As an example, consider:
class CircularConsts{
// Illegal program - mutually recursive compile-time constants
static const i = j; // a compile-time constant
static const j = i; // a compile-time constant
}
literal:
nullLiteral |
booleanLiteral |
numericLiteral |
stringLiteral |
symbolLiteral |
mapLiteral |
listLiteral
;
12.2 Null
The reserved word null denotes the null object.
nullLiteral:
null
Dart Programming Language Specication 48
;
The null object is the sole instance of the built-in class Null. Attempting to
instantiate Null causes a run-time error. It is a compile-time error for a class
to attempt to extend or implement Null. Invoking a method on null yields a
NoSuchMethodError unless the method is explicitly implemented by class Null.
The static type of null is .
The decision to use instead of Null allows null to be be assigned everywhere
without complaint by the static checker.
12.3 Numbers
A numeric literal is either a decimal or hexadecimal integer of arbitrary size, or
a decimal double.
numericLiteral:
NUMBER |
HEX NUMBER
;
NUMBER:
DIGIT+ (. DIGIT+)? EXPONENT? |
. DIGIT+ EXPONENT?
;
EXPONENT:
(e | E) (+ | -)? DIGIT+
;
HEX NUMBER:
0x HEX DIGIT+ |
0X HEX DIGIT+
;
HEX DIGIT:
a..f |
A..F |
DIGIT
;
If a numeric literal begins with the prex 0x or 0X, it denotes the hex-
adecimal integer represented by the part of the literal following 0x (respectively
Dart Programming Language Specication 49
0X). Otherwise, if the numeric literal does not include a decimal point it de-
notes a decimal integer. Otherwise, the numeric literal denotes a 64 bit double
precision oating point number as specied by the IEEE 754 standard.
In principle, the range of integers supported by a Dart implementations is
unlimited. In practice, it is limited by available memory. Implementations may
also be limited by other considerations.
For example, implementations may choose to limit the range to facilitate ef-
cient compilation to Javascript. These limitations should be relaxed as soon as
technologically feasible.
It is a compile-time error for a class to attempt to extend or implement int.
It is a compile-time error for a class to attempt to extend or implement double.
It is a compile-time error for any type other than the types int and double to
attempt to extend or implement num.
An integer literal is either a hexadecimal integer literal or a decimal integer
literal. Invoking the getter runtimeType on an integer literal returns the Type
object that is the value of the expression int. The static type of an integer literal
is int.
A literal double is a numeric literal that is not an integer literal. Invoking
the getter runtimeType on a literal double returns the Type object that is the
value of the expression double. The static type of a literal double is double.
12.4 Booleans
The reserved words true and false denote objects that represent the boolean
values true and false respectively. They are the boolean literals.
booleanLiteral:
true |
false
;
Both true and false implement the built-in class bool. It is a compile-time
error for a class to attempt to extend or implement bool.
It follows that the two boolean literals are the only two instances of bool.
Invoking the getter runtimeType on a boolean literal returns the Type object
that is the value of the expression bool. The static type of a boolean literal is
bool.
12.4.1 Boolean Conversion
Boolean conversion maps any object o into a boolean. Boolean conversion is
dened by the function
(bool v){
assert(v != null);
return identical(v, true);
}(o)
Dart Programming Language Specication 50
Boolean conversion is used as part of control-ow constructs and boolean
expressions. Ideally, one would simply insist that control-ow decisions be based
exclusively on booleans. This is straightforward in a statically typed setting. In
a dynamically typed language, it requires a dynamic check. Sophisticated virtual
machines can minimize the penalty involved. Alas, Dart must be compiled into
Javascript. Boolean conversion allows this to be done eciently.
At the same time, this formulation diers radically from Javascript, where
most numbers and objects are interpreted as true. Darts approach prevents
usages such if (a-b) ... ; because it does not agree with the low level conventions
whereby non-null objects or non-zero numbers are treated as true. Indeed, there
is no way to derive true from a non-boolean object via boolean conversion, so
this kind of low level hackery is nipped in the bud.
Dart also avoids the strange behaviors that can arise due to the interaction
of boolean conversion with autoboxing in Javascript. A notorious example is the
situation where false can be interpreted as true. In Javascript, booleans are
not objects, and instead are autoboxed into objects where needed. If false gets
autoboxed into an object, that object can be coerced into true (as it is a non-null
object).
Because boolean conversion requires its parameter to be a boolean, any con-
struct that makes use of boolean conversion will cause a dynamic type error in
checked mode if the value to be converted is not a boolean.
12.5 Strings
A string is a sequence of UTF-16 code units.
This decision was made for compatibility with web browsers and Javascript.
Earlier versions of the specication required a string to be a sequence of valid
Unicode code points. Programmers should not depend on this distinction.
stringLiteral:
(multilineString | singleLineString)+
;
A string can be either a sequence of single line strings or a multiline string.
singleLineString:
stringContentDQ* |
stringContentSQ* |
r (( | NEWLINE ))* |
r (( | NEWLINE ))*
;
A single line string is delimited by either matching single quotes or matching
double quotes.
Dart Programming Language Specication 51
Hence, abc and abc are both legal strings, as are He said To be or not to
be did he not? and He said To be or not to be didnt he. However This is
not a valid string, nor is this.
The grammar ensures that a single line string cannot span more than one line of
source code, unless it includes an interpolated expression that spans multiple lines.
Adjacent strings are implicitly concatenated to form a single string literal.
Here is an example
print(A string and then another); // prints: A stringand then another
Dart also supports the operator + for string concatenation.
The + operator on Strings requires a String argument. It does not coerce its
argument into a string. This helps avoid puzzlers such as
print(A simple sum: 2 + 2 = +
2 + 2);
which this prints A simple sum: 2 + 2 = 22 rather than A simple sum:
2 + 2 = 4. However, the use the concatenation operation is still discouraged
for eciency reasons. Instead, the recommended Dart idiom is to use string
interpolation.
print(A simple sum: 2 + 2 = ${2+2});
String interpolation work well for most cases. The main situation where it
is not fully satisfactory is for string literals that are too large to t on a line.
Multiline strings can be useful, but in some cases, we want to visually align the
code. This can be expressed by writing smaller strings separated by whitespace,
as shown here:
Imagine this is a very long string that does not t on a line. What shall we do?
Oh what shall we do?
We shall split it into pieces
like so.
multilineString:
""" stringContentTDQ* """ |
stringContentTSQ* |
r """ ( """)* """ |
r ( )*
;
ESCAPE SEQUENCE:
\ n |
\ r |
\ f |
\ b |
\ t |
\ v |
\ x HEX DIGIT HEX DIGIT |
\ u HEX DIGIT HEX DIGIT HEX DIGIT HEX DIGIT |
\ u{ HEX DIGIT SEQUENCE }
Dart Programming Language Specication 52
;
HEX DIGIT SEQUENCE:
HEX DIGIT HEX DIGIT? HEX DIGIT? HEX DIGIT? HEX DIGIT?
HEX DIGIT?
;
Multiline strings are delimited by either matching triples of single quotes or
matching triples of double quotes. If the rst line of a multiline string consists
solely of the whitespace characters dened by the production WHITESPACE
16.1), possibly prexed by \, then that line is ignored, including the new line
at its end.
The idea is to ignore whitespace, where whitespace is dened as tabs, spaces
and newlines. These can be represented directly, but since for most characters
prexing by backslash is an identity, we allow those forms as well.
Strings support escape sequences for special characters. The escapes are:
\n for newline, equivalent to \x0A.
\r for carriage return, equivalent to \x0D.
\f for form feed, equivalent to \x0C.
\b for backspace, equivalent to \x08.
\t for tab, equivalent to \x09.
\v for vertical tab, equivalent to \x0B
\x HEX DIGIT
1
HEX DIGIT
2
, equivalent to
\u{HEX DIGIT
1
HEX DIGIT
2
}.
\u HEX DIGIT
1
HEX DIGIT
2
HEX DIGIT
3
HEX DIGIT
4
, equiv-
alent to \u{HEX DIGIT
1
HEX DIGIT
2
HEX DIGIT
3
HEX DIGIT
4
}.
\u{HEX DIGIT SEQUENCE} is the unicode scalar value represented
by the HEX DIGIT SEQUENCE. It is a compile-time error if the
value of the HEX DIGIT SEQUENCE is not a valid unicode scalar
value.
$ indicating the beginning of an interpolated expression.
Otherwise, \k indicates the character k for any k not in {n, r, f, b, t, v, x, u}.
Any string may be prexed with the character r, indicating that it is a raw
string, in which case no escapes or interpolations are recognized.
It is a compile-time error if a non-raw string literal contains a character se-
quence of the form \x that is not followed by a sequence of two hexadecimal
Dart Programming Language Specication 53
digits. It is a compile-time error if a non-raw string literal contains a charac-
ter sequence of the form \u that is not followed by either a sequence of four
hexadecimal digits, or by curly brace delimited sequence of hexadecimal digits.
stringContentDQ:
( \ | " | $ | NEWLINE ) |
\ ( NEWLINE ) |
stringInterpolation
;
stringContentSQ:
( \ | | $ | NEWLINE ) |
\ ( NEWLINE ) |
stringInterpolation
;
stringContentTDQ:
( \ | """ | $) |
stringInterpolation
;
stringContentTSQ:
( \ | | $) |
stringInterpolation
;
NEWLINE:
\ n |
\ r
;
All string literals implement the built-in class String. It is a compile-time
error for a class to attempt to extend or implement String. Invoking the getter
runtimeType on a string literal returns the Type object that is the value of the
expression String. The static type of a string literal is String.
12.5.1 String Interpolation
It is possible to embed expressions within non-raw string literals, such that
the these expressions are evaluated, and the resulting values are converted into
strings and concatenated with the enclosing string. This process is known as
string interpolation.
stringInterpolation:
$ IDENTIFIER NO DOLLAR |
Dart Programming Language Specication 54
$ { expression }
;
The reader will note that the expression inside the interpolation could itself
include strings, which could again be interpolated recursively.
An unescaped $ character in a string signies the beginning of an interpo-
lated expression. The $ sign may be followed by either:
A single identier id that must not contain the $ character.
An expression e delimited by curly braces.
The form $id is equivalent to the form ${id}. An interpolated string s
1
${e}s
2
;
A unary expression is either a postx expression (12.29), an invocation of a
prex operator on an expression or an invocation of a unary operator on either
super or an expression e.
The expression !e is equivalent to the expression e?false : true.
Evaluation of an expression of the form ++e is equivalent to e += 1. Eval-
uation of an expression of the form --e is equivalent to e -= 1.
An expression of the form op e is equivalent to the method invocation e.op().
An expression of the form op super is equivalent to the method invocation
super.op().
12.29 Postx Expressions
Postx expressions invoke the postx operators on objects.
postxExpression:
assignableExpression postxOperator |
primary selector*
;
postxOperator:
incrementOperator
;
selector:
assignableSelector |
arguments
;
incrementOperator:
++ |
--
;
A postx expression is either a primary expression, a function, method or
getter invocation, or an invocation of a postx operator on an expression e.
A postx expression of the form v++, where v is an identier, is equivalent
to (){var r = v; v = r + 1; return r}().
Dart Programming Language Specication 83
The above ensures that if v is a eld, the getter gets called exactly once.
Likewise in the cases below.
A postx expression of the form C.v ++ is equivalent to
(){var r = C.v; C.v = r + 1; return r}().
A postx expression of the form e
1
.v++ is equivalent to
(x){var r = x.v; x.v = r + 1; return r}(e
1
).
A postx expression of the form e
1
[e
2
]++, is equivalent to
(a, i){var r = a[i]; a[i] = r + 1; return r}(e
1
, e
2
).
A postx expression of the form v--, where v is an identier, is equivalent to
(){var r = v; v = r - 1; return r}().
A postx expression of the form C.v-- is equivalent to
(){var r = C.v; C.v = r - 1; return r}().
A postx expression of the form e
1
.v-- is equivalent to
(x){var r = x.v; x.v = r - 1; return r}(e
1
).
A postx expression of the form e
1
[e
2
]--, is equivalent to
(a, i){var r = a[i]; a[i] = r - 1; return r}(e
1
, e
2
).
12.30 Assignable Expressions
Assignable expressions are expressions that can appear on the left hand side of
an assignment. This section describes how to evaluate these expressions when
they do not constitute the complete left hand side of an assignment.
Of course, if assignable expressions always appeared as the left hand side,
one would have no need for their value, and the rules for evaluating them would
be unnecessary. However, assignable expressions can be subexpressions of other
expressions and therefore must be evaluated.
assignableExpression:
primary (argument* assignableSelector)+ |
super assignableSelector |
identier
;
assignableSelector:
[ expression ] |
. identier
;
An assignable expression is either:
An identier.
An invocation of a getter (7.2) or list access operator on an expression e.
An invocation of a getter or list access operator on super.
Dart Programming Language Specication 84
An assignable expression of the form id is evaluated as an identier expres-
sion (12.31).
An assignable expression of the form e.id is evaluated as a getter invocation
(12.18).
An assignable expression of the form e
1
[e
2
] is evaluated as a method invo-
cation of the operator method [] on e
1
with argument e
2
.
An assignable expression of the form super.id is evaluated as a getter invo-
cation.
An assignable expression of the form super[e
2
] is equivalent to the method
invocation super.[](e
2
).
12.31 Identier Reference
An identier expression consists of a single identier; it provides access to an
object via an unqualied name.
identier:
IDENTIFIER
;
IDENTIFIER NO DOLLAR:
IDENTIFIER START NO DOLLAR IDENTIFIER PART NO DOLLAR*
;
IDENTIFIER:
IDENTIFIER START IDENTIFIER PART*
;
BUILT IN IDENTIFIER:
abstract |
as |
dynamic |
export |
external |
factory |
get |
implements |
import |
library |
operator |
part |
set |
static |
typedef
Dart Programming Language Specication 85
;
IDENTIFIER START:
IDENTIFIER START NO DOLLAR |
$
;
IDENTIFIER START NO DOLLAR:
LETTER |
;
IDENTIFIER PART NO DOLLAR:
IDENTIFIER START NO DOLLAR |
DIGIT
;
IDENTIFIER PART:
IDENTIFIER START |
DIGIT
;
qualied:
identier (. identier)?
;
A built-in identier is one of the identiers produced by the production
BUILT IN IDENTIFIER. It is a compile-time error if a built-in identier is
used as the declared name of a class, type parameter or type alias. It is a
compile-time error to use a built-in identier other than dynamic as a type
annotation.
Built-in identiers are identiers that are used as keywords in Dart, but are
not reserved words in Javascript. To minimize incompatibilities when porting
Javascript code to Dart, we do not make these into reserved words. A built-in
identier may not be used to name a class or type. In other words, they are
treated as reserved words when used as types. This eliminates many confus-
ing situations without causing compatibility problems. After all, a Javascript
program has no type declarations or annotations so no clash can occur. Fur-
thermore, types should begin with an uppercase letter (see the appendix) and so
no clash should occur in any Dart user program anyway.
Evaluation of an identier expression e of the form id proceeds as follows:
Let d be the innermost declaration in the enclosing lexical scope whose name
is id or id =. If no such declaration exists in the lexical scope, let d be the
declaration of the inherited member named id if it exists.
Dart Programming Language Specication 86
If d is a class or type alias T, the value of e is an instance of class Type
reifying T.
If d is a type parameter T, then the value of e is the value of the actual
type argument corresponding to T that was passed to the generative con-
structor that created the current binding of this. If, however, e occurs
inside a static member, a compile-time error occurs.
If d is a constant variable of one of the forms const v = e; or const T v
= e; then the value id is the value of the compile-time constant e.
If d is a local variable or formal parameter then e evaluates to the current
binding of id.
If d is a static method, top-level function or local function then e evaluates
to the function dened by d.
If d is the declaration of a static variable, static getter or static setter
declared in class C, then e is equivalent to the getter invocation (12.18)
C.id.
If d is the declaration of a library variable, top-level getter or top-level
setter, then e is equivalent to the getter invocation id.
Otherwise, if e occurs inside a top level or static function (be it function,
method, getter, or setter) or variable initializer, evaluation of e causes a
NoSuchMethod to be thrown.
Otherwise, e is equivalent to the property extraction (12.14) this.id.
The static type of e is determined as follows:
If d is a class, type alias or type parameter the static type of e is Type.
If d is a local variable or formal parameter the static type of e is the type
of the variable id, unless id is known to have some type T, in which case
the static type of e is T, provided that T is more specic than any other
type S such that v is known to have type S.
If d is a static method, top-level function or local function the static type
of e is the function type dened by d.
If d is the declaration of a static variable, static getter or static setter
declared in class C, the static type of e is the static type of the getter
invocation (12.18) C.id.
If d is the declaration of a library variable, top-level getter or top-level
setter, the static type of e is the static type of the getter invocation id.
Otherwise, if e occurs inside a top level or static function (be it function,
method, getter, or setter) or variable initializer, the static type of e is
dynamic.
Dart Programming Language Specication 87
Otherwise, the static type of e is the type of the property extraction (12.14)
this.id.
Note that if one declares a setter, we bind to the corresponding getter even if it
does not exist.
This prevents situations where one uses uncorrelated setters and getters.
The intent is to prevent errors when a getter in a surrounding scope is used
accidentally.
It is a static warning if an identier expression id occurs inside a top level or
static function (be it function, method, getter, or setter) or variable initializer
and there is no declaration d with name id in the lexical scope enclosing the
expression.
12.32 Type Test
The is-expression tests if an object is a member of a type.
typeTest:
isOperator type
;
isOperator:
is ! ?
;
Evaluation of the is-expression e is T proceeds as follows:
The expression e is evaluated to a value v. Then, if T is malformed, a
dynamic error occurs. Otherwise, if the interface of the class of v is a subtype
of T, the is-expression evaluates to true. Otherwise it evaluates to false.
It follows that e is Object is always true. This makes sense in a language where
everything is an object.
Also note that null is T is false unless T = Object, T = dynamic or T = Null.
The former two are useless, as is anything of the form e is Object or e is dynamic.
Users should test for a null value directly rather than via type tests.
The is-expression e is! T is equivalent to !(e is T).
Let v be a local variable or a formal parameter. An is-expression of the form
v is T shows that v has type T i T is more specic than the type S of the
expression v and both T = dynamic and S = dynamic.
The motivation for the shows that v has type T relation is to reduce spu-
rious warnings thereby enabling a more natural coding style. The rules in the
current specication are deliberately kept simple. It would be upwardly compati-
ble to rene these rules in the future; such a renement would accept more code
without warning, but not reject any code now warning-free.
The rule only applies to locals and parameters, as elds could be modied via
side-eecting functions or methods that are not accessible to a local analysis.
Dart Programming Language Specication 88
It is pointless to deduce a weaker type than what is already known. Further-
more, this would lead to a situation where multiple types are associated with a
variable at a given point, which complicates the specication. Hence the require-
ment that T << S (we use << rather than subtyping because subtyping is not
a partial order).
We do not want to rene the type of a variable of type dynamic, as this
could lead to more warnings rather than less. The opposite requirement, that
T = dynamic is a safeguard lest S ever be .
The static type of an is-expression is bool.
12.33 Type Cast
The cast expression ensures that an object is a member of a type.
typeCast:
asOperator type
;
asOperator:
as
;
Evaluation of the cast expression e as T proceeds as follows:
The expression e is evaluated to a value v. Then, if T is malformed, a
dynamic error occurs. Otherwise, if the interface of the class of v is a subtype of
T, the cast expression evaluates to v. Otherwise, if v is null, the cast expression
evaluates to v. In all other cases, a CastError is thrown.
The static type of a cast expression e as T is T.
13 Statements
statements:
statement*
;
statement:
label* nonLabelledStatement
;
nonLabelledStatement:
block |
localVariableDeclaration |
forStatement |
whileStatement |
Dart Programming Language Specication 89
doStatement |
switchStatement |
ifStatement |
rethrowStatement |
tryStatement |
breakStatement |
continueStatement |
returnStatement |
expressionStatement |
assertStatement |
localFunctionDeclaration
;
13.1 Blocks
A block statement supports sequencing of code.
Execution of a block statement {s
1
, . . . , s
n
} proceeds as follows:
For i 1..n, s
i
is executed.
A block statement introduces a new scope, which is nested in the lexically
enclosing scope in which the block statement appears.
13.2 Expression Statements
An expression statement consists of an expression other than a non-constant
map literal (12.8) that has no explicit type arguments.
The restriction on maps is designed to resolve an ambiguity in the grammar,
when a statement begins with {.
expressionStatement:
expression? ;
;
Execution of an expression statement e; proceeds by evaluating e.
It is a compile-time error if a non-constant map literal that has no explicit
type arguments appears in a place where a statement is expected.
13.3 Local Variable Declaration
A variable declaration statement declares a new local variable.
localVariableDeclaration:
initializedVariableDeclaration ;
;
Dart Programming Language Specication 90
Executing a variable declaration statement of one of the forms var v = e;,
T v = e;, const v = e;, const T v = e;, nal v = e; or nal T v = e; proceeds
as follows:
The expression e is evaluated to an object o. Then, the variable v is set to
o.
A variable declaration statement of the form var v; is equivalent to var
v = null;. A variable declaration statement of the form T v; is equivalent to T
v = null;.
This holds regardless of the type T. For example, int i; does not cause i to be
initialized to zero. Instead, i is initialized to null, just as if we had written var i; or
Object i; or Collection<String> i;.
To do otherwise would undermine the optionally typed nature of Dart, caus-
ing type annotations to modify program behavior.
13.4 Local Function Declaration
A function declaration statement declares a new local function (6.1).
localFunctionDeclaration:
functionSignature functionBody
;
A function declaration statement of one of the forms id signature {statements}
or T id signature {statements} causes a new function named id to be added
to the innermost enclosing scope. It is a compile-time error to reference a local
function before its declaration.
This implies that local functions can be directly recursive, but not mutually
recursive. Consider these examples:
f(x) => x++; // a top level function
top() { // another top level function
f(3); // illegal
f(x) => x > 0? x*f(x-1): 1; // recursion is legal
g1(x) => h(x, 1); // error: h is not declared yet
h(x, n) => x > 1? h(x-1, n*x): n; // again, recursion is ne
g2(x) => h(x, 1); // legal
p1(x) => q(x,x); // illegal
q1(a, b) => a > 0 ? p1(a-1): b; // ne
q2(a, b) => a > 0 ? p2(a-1): b; // illegal
p1(x) => q2(x,x); // ne
}
There is no way to write a pair of mutually recursive local functions, because
one always has to come before the other is declared. These cases are quite rare,
and can always be managed by dening a pair of variables rst, then assigning them
appropriate closures:
top2() { // a top level function
Dart Programming Language Specication 91
var p, q;
p = (x) => q(x,x);
q = (a, b) => a > 0 ? p(a-1): b;
}
The rules for local functions dier slightly from those for local variables in
that a function can be accessed within its declaration but a variable can only
be accessed after its declaration. This is because recursive functions are use-
ful whereas recursively dened variables are almost always errors. It therefore
makes sense to harmonize the rules for local functions with those for functions
in general rather than with the rules for local variables.
13.5 If
The if statement allows for conditional execution of statements.
ifStatement:
if ( expression ) statement ( else statement)?
;
Execution of an if statement of the form if (b)s
1
else s
2
proceeds as follows:
First, the expression b is evaluated to an object o. Then, o is subjected
to boolean conversion (12.4.1), producing an object r. If r is true, then the
statement {s
1
} is executed, otherwise statement {s
2
} is executed.
Put another way, if (b)s
1
else s
2
is equivalent to if (b){s
1
} else {s
2
}
The reason for this equivalence is to catch errors such as
void main() {
if (somePredicate)
var v = 2;
print(v);
}
Under reasonable scope rules such code is problematic. If we assume that v
is declared in the scope of the method main(), then when somePredicate is false, v
will be uninitialized when accessed. The cleanest approach would be to require a
block following the test, rather than an arbitrary statement. However, this goes
against long standing custom, undermining Darts goal of familiarity. Instead,
we choose to insert a block, introducing a scope, around the statement following
the predicate (and similarly for else and loops). This will cause both a warning
and a runtime error in the case above. Of course, if there is a declaration of v
in the surrounding scope, programmers might still be surprised. We expect tools
to highlight cases of shadowing to help avoid such situations.
It is a static type warning if the type of the expression b may not be assigned
to bool.
If:
b shows that a variable v has type T.
Dart Programming Language Specication 92
v is not potentially mutated in s
1
or within a closure.
If the variable v is accessed by a closure in s
1
then the variable v is not
potentially mutated anywhere in the scope of v.
then the type of v is known to be T in s
1
.
An if statement of the form if (b)s
1
is equivalent to the if statement
if (b)s
1
else {}.
13.6 For
The for statement supports iteration.
forStatement:
for ( forLoopParts ) statement
;
forLoopParts:
forInitializerStatement expression? ; expressionList? |
declaredIdentier in expression |
identier in expression
;
forInitializerStatement:
localVariableDeclaration ; |
expression? ;
;
The for statement has two forms - the traditional for loop and the for-in
statement.
13.6.1 For Loop
Execution of a for statement of the form for (var v = e
0
; c; e) s proceeds as
follows:
If c is empty then let c
be c.
First the variable declaration statement var v = e
0
is executed. Then:
1. If this is the rst iteration of the for loop, let v
be v. Otherwise, let v
be
the variable v
/v]{s} is executed.
Dart Programming Language Specication 93
4. Let v
be a fresh variable. v
.
5. The expression [v