-
Notifications
You must be signed in to change notification settings - Fork 1
/
dartLangSpec.tex
7695 lines (5476 loc) · 408 KB
/
dartLangSpec.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass{article}
\usepackage{epsfig}
\usepackage{color}
\usepackage{dart}
\usepackage{bnf}
\usepackage{hyperref}
\usepackage{lmodern}
\newcommand{\code}[1]{{\sf #1}}
\title{Dart Programming Language Specification \\
{\large Version 1.9}}
% For information about Location Markers (and in particular the
% commands \LMHash and \LMLabel), see the long comment at the
% end of this file.
\begin{document}
\maketitle
\tableofcontents
\newpage
\pagestyle{myheadings}
\markright{Dart Programming Language Specification}
% begin Ecma boilerplate
\section{Scope}
\LMLabel{ecmaScope}
\LMHash{}
This Ecma standard specifies the syntax and semantics of the Dart programming language. It does not specify the APIs of the Dart libraries except where those library elements are essential to the correct functioning of the language itself (e.g., the existence of class \cd{Object} with methods such as \cd{noSuchMethod}, \cd{runtimeType}).
\section{Conformance}
\LMLabel{ecmaConformance}
\LMHash{}
A conforming implementation of the Dart programming language must provide and support all the APIs (libraries, types, functions, getters, setters, whether top-level, static, instance or local) mandated in this specification.
\LMHash{}
A conforming implementation is permitted to provide additional APIs, but not additional syntax, except for experimental features in support of null-aware cascades and tear-offs that are likely to be introduced in the next revision of this specification.
\section{Normative References}
\LMLabel{ecmaNormativeReferences}
\LMHash{}
The following referenced documents are indispensable for the application of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.
\begin{enumerate}
\item
The Unicode Standard, Version 5.0, as amended by Unicode 5.1.0, or successor.
\item
Dart API Reference, https://api.dartlang.org/
\end{enumerate}
\section{Terms and Definitions}
\LMLabel{ecmaTermsAndDefinitions}
\LMHash{}
Terms and definitions used in this specification are given in the body of the specification proper. Such terms are highlighted in italics when they are introduced, e.g., `we use the term {\em verbosity} to refer to the property of excess verbiage'.
% End Ecma Boilerplate
\section{Notation}
\LMLabel{notation}
\LMHash{}
We distinguish between normative and non-normative text. Normative text defines the rules of Dart. It is given in this font. At this time, non-normative text includes:
\begin{itemize}
\item[Rationale] Discussion of the motivation for language design decisions appears in italics. \rationale{Distinguishing normative from non-normative helps clarify what part of the text is binding and what part is merely expository.}
\item[Commentary] Comments such as ``\commentary{The careful reader will have noticed that the name Dart has four characters}'' serve to illustrate or clarify the specification, but are redundant with the normative text. \commentary{The difference between commentary and rationale can be subtle.} \rationale{ Commentary is more general than rationale, and may include illustrative examples or clarifications. }
\item[Open questions] (\Q{in this font}). Open questions are points that are unsettled in the mind of the author(s) of the specification; expect them (the questions, not the authors; precision is important in a specification) to be eliminated in the final specification. \Q{Should the text at the end of the previous bullet be rationale or commentary?}
\end{itemize}
\LMHash{}
Reserved words and built-in identifiers (\ref{identifierReference}) appear in {\bf bold}.
\commentary{
Examples would be \SWITCH{} or \CLASS{}.
}
\LMHash{}
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, alternation is represented by vertical bars, and sequencing by spacing. As in PEGs, alternation gives priority to the left. Optional elements of a production are suffixed by a question mark like so: \code{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 prefixing 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.
\commentary{ An example would be:}
\begin{grammar}
{\sf
{\bf AProduction:}AnAlternative;
AnotherAlternative;
OneThing After Another;
ZeroOrMoreThings*;
OneOrMoreThings+;
AnOptionalThing?;
(Some Grouped Things);
\~{}NotAThing;
A\_LEXICAL\_THING
.
}
\end{grammar}
% need a match anything or a production that does that, so we can correct bugs wrt use
% ~. ~ does not actually parse stuff - it just looks ahead and checks. To get the effect of
% parsing anything but X, one needs ~X ANYTHING, not just ~X. There are bugs in the
% grammar related to this.
% The alternative is to define ~X as anything but X, or to introduce an anthingBut(X)
% combinator, such as !X
\LMHash{}
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.
\LMHash{}
Productions are embedded, as much as possible, in the discussion of the constructs they represent.
\LMHash{}
A list $x_1, \ldots, x_n$ denotes any list of $n$ elements of the form $x_i, 1 \le i \le n$. Note that $n$ may be zero, in which case the list is empty. We use such lists extensively throughout this specification.
\LMHash{}
The notation $[x_1, \ldots, x_n/y_1, \ldots, y_n]E$ denotes a copy of $E$ in which all occurrences of $y_i, 1 \le i \le n$ have been replaced with $x_i$.
\LMHash{}
We sometimes abuse list or map literal syntax, writing $[o_1, \ldots, o_n]$ (respectively $\{k_1: o_1, \ldots, 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$).
\LMHash{}
The specifications of operators often involve statements such as $x$ $op$ $y$ is equivalent to the method invocation $x.op(y)$. Such specifications should be understood as a shorthand for:
\begin{itemize}
\item
$x$ $op$ $y$ is equivalent to the method invocation $x.op^\prime(y)$, assuming the class of $x$ actually declared a non-operator method named $op^\prime$ defining the same function as the operator $op$.
\end{itemize}
\rationale{This circumlocution is required because x.op(y), where op is an operator, is not legal syntax. However, it is painfully verbose, and we prefer to state this rule once here, and use a concise and clear notation across the specification.
}
\LMHash{}
When the specification refers to the order given in the program, it means the order of the program source code text, scanning left-to-right and top-to-bottom.
\LMHash{}
References to otherwise unspecified names of program entities (such as classes or functions) are interpreted as the names of members of the Dart core library.
\commentary{
Examples would be the classes \code{Object} and \code{Type} representing the root of the class hierarchy and the reification of runtime types respectively.
}
\section{Overview}
\LMLabel{overview}
\LMHash{}
Dart is a class-based, single-inheritance, pure object-oriented programming language. Dart is optionally typed (\ref{types}) and supports reified generics. The run-time type of every object is represented as an instance of class \code{Type} which can be obtained by calling the getter \code{runtimeType} declared in class \code{Object}, the root of the Dart class hierarchy.
\LMHash{}
Dart programs may be statically checked. The static checker will report some violations of the type rules, but such violations do not abort compilation or preclude execution.
\LMHash{}
Dart programs may be executed in one of two modes: production mode or checked mode. In production mode, static type annotations (\ref{staticTypes}) have absolutely no effect on execution with the exception of reflection and structural type tests.
\commentary{
Reflection, by definition, examines the program structure. If we provide reflective access to the type of a declaration, or to source code, it will inevitably produce results that depend on the types used in the underlying code.
Type tests also examine the types in a program explicitly. Nevertheless, in most cases, these will not depend on type annotations. The exceptions to this rule are type tests involving function types. Function types are structural, and so depend on the types declared for their parameters and on their return types.
}
\LMHash{}
In checked mode, assignments are dynamically checked, and certain violations of the type system raise exceptions at run time.
\commentary{
The coexistence between optional typing and reification is based on the following:
\begin{enumerate}
\item Reified type information reflects the types of objects at runtime and may always be queried by dynamic typechecking constructs (the analogs of instanceOf, casts, typecase etc. in other languages). Reified type information includes class declarations, the runtime type (aka class) of an object, and type arguments to constructors.
\item Static type annotations determine the types of variables and function declarations (including methods and constructors).
\item Production mode respects optional typing. Static type annotations do not affect runtime behavior.
\item Checked mode utilizes static type annotations and dynamic type information aggressively yet selectively to provide early error detection during development.
\end{enumerate}
}
\LMHash{}
Dart programs are organized in a modular fashion into units called {\em libraries} (\ref{librariesAndScripts}). Libraries are units of encapsulation and may be mutually recursive.
\commentary{However they are not first class. To get multiple copies of a library running simultaneously, one needs to spawn an isolate.
}
\subsection{Scoping}
\LMLabel{scoping}
\LMHash{}
A {\em namespace} is a mapping of names denoting declarations to actual declarations. Let $NS$ be a namespace. We say that a name $n$ {\em is in }$NS$ if $n$ is a key of $NS$. We say a declaration $d$ {\em is in }$NS$ if a key of $NS$ maps to $d$.
\LMHash{}
A scope $S_0$ induces a namespace $NS_0$ that maps the simple name of each variable, type or function declaration $d$ declared in $S_0$ to $d$. Labels are not included in the induced namespace of a scope; instead they have their own dedicated namespace.
\commentary{It is therefore impossible, e.g., to define a class that declares a method and a field with the same name in Dart. Similarly one cannot declare a top-level function with the same name as a library variable or class.
}
\LMHash{}
It is a compile-time error if there is more than one entity with the same name declared in the same scope.
\commentary{
In some cases, the name of the declaration differs from the identifier used to declare it. Setters have names that are distinct from the corresponding getters because they always have an = automatically added at the end, and unary minus has the special name unary-.
}
\LMHash{}
Dart is lexically scoped. Scopes may nest. A name or declaration $d$ is {\em available in scope} $S$ if $d$ is in the namespace induced by $S$ or if $d$ is available in the lexically enclosing scope of $S$. We say that a name or declaration $d$ is {\em in scope} if $d$ is available in the current scope.
\LMHash{}
If a declaration $d$ named $n$ is in the namespace induced by a scope $S$, then $d$ {\em hides} any declaration named $n$ that is available in the lexically enclosing scope of $S$.
\commentary {
A consequence of these rules is that it is possible to hide a type with a method or variable.
Naming conventions usually prevent such abuses. Nevertheless,the following program is legal:
}
\begin{dartCode}
\CLASS{} HighlyStrung \{
String() $=>$ "?";
\}
\end{dartCode}
\LMHash{}
Names may be introduced into a scope by declarations within the scope or by other mechanisms such as imports or inheritance.
\rationale{
The interaction of lexical scoping and inheritance is a subtle one. Ultimately, the question is whether lexical scoping takes precedence over inheritance or vice versa. Dart chooses the former.
Allowing inherited names to take precedence over locally declared names can create unexpected situations as code evolves. Specifically, the behavior of code in a subclass can change without warning if a new name is introduced in a superclass. Consider:
}
\begin{dartCode}
\LIBRARY{} L1;
\CLASS{} S \{\}
\LIBRARY{} L2;
\IMPORT{} `L1.dart';
foo() =$>$ 42;
\CLASS{} C \EXTENDS{} S\{ bar() =$>$ foo();\}
\end{dartCode}
\rationale{Now assume a method \code{foo()} is added to \code{S}. }
\begin{dartCode}
\LIBRARY{} L1;
\CLASS{} S \{foo() =$>$ 91;\}
\end{dartCode}
\rationale{
If inheritance took precedence over the lexical scope, the behavior of \code{C} would change in an unexpected way. Neither the author of \code{S} nor the author of \code{C} are necessarily aware of this. In Dart, if there is a lexically visible method \code{foo()}, it will always be called.
Now consider the opposite scenario. We start with a version of \code{S} that contains \code{foo()}, but do not declare \code{foo()} in library \code{L2}. Again, there is a change in behavior - but the author of \code{L2} is the one who introduced the discrepancy that effects their code, and the new code is lexically visible. Both these factors make it more likely that the problem will be detected.
These considerations become even more important if one introduces constructs such as nested classes, which might be considered in future versions of the language.
Good tooling should of course endeavor to inform programmers of such situations (discreetly). For example, an identifier that is both inherited and lexically visible could be highlighted (via underlining or colorization). Better yet, tight integration of source control with language aware tools would detect such changes when they occur.
}
\subsection{Privacy}
\LMLabel{privacy}
\LMHash{}
Dart supports two levels of privacy: {\em public} and {\em private}. A declaration is {\em private} iff its name is private, otherwise it is {\em public.} A name $q$ is private iff any one of the identifiers that comprise $q$ is private, otherwise it is {\em public.} An identifier is private iff it
begins with an underscore (the \_ character) otherwise it is {\em public.}
\LMHash{}
A declaration $m$ is {\em accessible to library $L$} if $m$ is declared in $L$ or if $m$ is public.
\commentary{
This means private declarations may only be accessed within the library in which they are declared.
}
\LMHash{}
Privacy applies only to declarations within a library, not to library declarations themselves.
\rationale{Libraries do not reference each other by name and so the idea of a private library is meaningless.
Thus, if the name of a library begins with an underscore, it has no effect on the accessibility of the library or its members.
}
\rationale{Privacy is, at this point, a static notion tied to a particular piece of code (a library). It is designed to support software engineering concerns rather than security concerns. Untrusted code should always run in an another isolate. It is possible that libraries will become first class objects and privacy will be a dynamic notion tied to a library instance.
Privacy is indicated by the name of a declaration - hence privacy and naming are not orthogonal. This has the advantage that both humans and machines can recognize access to private declarations at the point of use without knowledge of the context from which the declaration is derived.}
\subsection{Concurrency}
\LMLabel{concurrency}
\LMHash{}
Dart code is always single threaded. There is no shared-state concurrency in Dart. Concurrency is supported via actor-like entities called {\em isolates}.
\LMHash{}
An isolate is a unit of concurrency. It has its own memory and its own thread of control. Isolates communicate by message passing (\ref{sendingMessages}). No state is ever shared between isolates. Isolates are created by spawning (\ref{spawningAnIsolate}).
\section{Errors and Warnings}
\LMLabel{errorsAndWarnings}
\LMHash{}
This specification distinguishes between several kinds of errors.
\LMHash{}
{\em Compile-time errors} are errors that preclude execution. A compile-time error must be reported by a Dart compiler before the erroneous code is executed.
\rationale{A Dart implementation has considerable freedom as to when compilation takes place. Modern programming language implementations often interleave compilation and execution, so that compilation of a method may be delayed, e.g., until it is first invoked. Consequently, compile-time errors in a method $m$ may be reported as late as the time of $m$'s first invocation.
As a web language, Dart is often loaded directly from source, with no intermediate binary representation. In the interests of rapid loading, Dart implementations may choose to avoid full parsing of method bodies, for example. This can be done by tokenizing the input and checking for balanced curly braces on method body entry. In such an implementation, even syntax errors will be detected only when the method needs to be executed, at which time it will be compiled (JITed).
In a development environment a compiler should of course report compilation errors eagerly so as to best serve the programmer.
}
\LMHash{}
If an uncaught compile-time error occurs within the code of a running isolate $A$, $A$ is immediately suspended. The only circumstance where a compile-time error could be caught would be via code run reflectively, where the mirror system can catch it.
\rationale{Typically, once a compile-time error is thrown and $A$ is suspended, $A$ will then be terminated. However, this depends on the overall environment.
A Dart engine runs in the context of an {\em embedder},
a program that interfaces between the engine and the surrounding computing environment. The embedder will often be a web browser, but need not be; it may be a C++ program on the server for example. When an isolate fails with a compile-time error as described above, control returns to the embedder, along with an exception describing the problem. This is necessary so that the embedder can clean up resources etc. It is then the embedder's decision whether to terminate the isolate or not.
}
\LMHash{}
{\em Static warnings} are those errors reported by the static checker. They have no effect on execution. Many, but not all, static warnings relate to types, in which case they are known as {\em static type warnings.} Static warnings must be provided by Dart compilers used during development such as those incorporated in IDEs or otherwise intended to be used by developers for developing code. Compilers that are part of runtime execution environments such as virtual machines should not issue static warnings.
\LMHash{}
{\em Dynamic type errors} are type errors reported in checked mode.
\LMHash{}
{\em Run-time errors} are exceptions raised during execution. Whenever we say that an exception $ex$ is {\em raised} or {\em thrown}, we mean that a throw expression (\ref{throw}) of the form: \code{\THROW{} $ex$;} was implicitly evaluated or that a rethrow statement (\ref{rethrow}) of the form \code{\RETHROW} was executed. When we say that {\em a} $C$ {\em is thrown}, where $C$ is a class, we mean that an instance of class $C$ is thrown.
\LMHash{}
If an uncaught exception is thrown by a running isolate $A$, $A$ is immediately suspended.
\section{Variables}
\LMLabel{variables}
\LMHash{}
Variables are storage locations in memory.
\begin{grammar}
{\bf variableDeclaration:}
declaredIdentifier (`,' identifier)*
.
{\bf declaredIdentifier:}
metadata finalConstVarOrType identifier
.
{\bf finalConstVarOrType:}\FINAL{} type?;
\CONST{} type?;
varOrType
.
{\bf varOrType:}\VAR{};
type
.
{\bf initializedVariableDeclaration:}
declaredIdentifier (`=' expression)? (`,' initializedIdentifier)* % could do top level here
.
{\bf initializedIdentifier:}
identifier (`=' expression)? % could do top-level here
.
{\bf initializedIdentifierList:}
initializedIdentifier (`,' initializedIdentifier)*
.
\end{grammar}
\LMHash{}
A variable that has not been initialized has the initial value \NULL{} (\ref{null}).
\LMHash{}
A variable declared at the top-level of a library is referred to as either a {\em library variable} or simply a top-level variable.
\LMHash{}
A {\em static variable} is a variable that is not associated with a particular instance, but rather with an entire library or class. Static variables include library variables and class variables. Class variables are variables whose declaration is immediately nested inside a class declaration and includes the modifier \STATIC{}. A library variable is implicitly static. It is a compile-time error to preface a top-level variable declaration with the built-in identifier (\ref{identifierReference}) \STATIC{}.
\LMHash{}
Static variable declarations are initialized lazily. When a static variable $v$ is read, iff it has not yet been assigned, it is set to the result of evaluating its initializer. The precise rules are given in section \ref{evaluationOfImplicitVariableGetters}.
\rationale{The lazy semantics are given 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 must support the coding of client applications.
}
\LMHash{}
A {\em final variable} is a variable whose binding is fixed upon initialization; a final variable $v$ will always refer to the same object after $v$ has been initialized. The declaration of a final variable must include the modifier \FINAL{}.
\LMHash{}
It is a static warning if a final instance variable that has been initialized at its point of declaration is also initialized in a constructor.
% It is a static warning if a final instance variable that has been initialized by means of an initializing formal of a constructor is also initialized elsewhere in the same constructor.
It is a compile-time error if a local variable $v$ is final and $v$ is not initialized at its point of declaration.
\commentary{
A library or static variable is guaranteed to have an initializer at its declaration by the grammar.
Attempting to assign to a final variable anywhere except in its declaration or in a constructor header will cause a runtime error to be thrown as discussed below. The assignment will also give rise to a static warning. Any repeated assignment to a final variable will also lead to a runtime error.
Taken as a whole, the rules ensure that any attempt to execute multiple assignments to a final variable will yield static warnings and repeated assignments will fail dynamically.
}
\LMHash{}
A {\em constant variable} is a variable whose declaration includes the modifier \CONST{}. A constant variable is always implicitly final. A constant variable must be initialized to a compile-time constant (\ref{constants}) or a compile-time error occurs.
\LMHash{}
We say that a variable $v$ is {\em potentially mutated} in some scope $s$ if $v$ is not final or constant and an assignment to $v$ occurs in $s$.
\LMHash{}
If a variable declaration does not explicitly specify a type, the type of the declared variable(s) is \DYNAMIC{}, the unknown type (\ref{typeDynamic}).
\LMHash{}
A variable is {\em mutable} if it is not final.
Static and instance variable declarations always induce implicit getters. If the variable is mutable it also introduces an implicit setter.
The scope into which the implicit getters and setters are introduced depends on the kind of variable declaration involved.
\LMHash{}
A library variable introduces a getter into the top level scope of the enclosing library. A static class variable introduces a static getter into the immediately enclosing class. An instance variable introduces an instance getter into the immediately enclosing class.
\LMHash{}
A mutable library variable introduces a setter into the top level scope of the enclosing library. A mutable static class variable introduces a static setter into the immediately enclosing class. A mutable instance variable introduces an instance setter into the immediately enclosing class.
\LMHash{}
Local variables are added to the innermost enclosing scope. They do not induce getters and setters. A local variable may only be referenced at a source code location that is after its initializer, if any, is complete, or a compile-time error occurs. The error may be reported either at the point where the premature reference occurs, or at the variable declaration.
\rationale {
We allow the error to be reported at the declaration to allow implementations to avoid an extra processing phase.
}
\commentary{
The example below illustrates the expected behavior. A variable $x$ is declared at the library level, and another $x$ is declared inside the function $f$.
}
\begin{dartCode}
\VAR{} x = 0;
f(y) \{
\VAR{} z = x; // compile-time error
if (y) \{
x = x + 1; // two compile time errors
print(x); // compile time error
\}
\VAR{} x = x++; // compile time error
print(x);
\}
\end{dartCode}
\commentary{
The declaration inside $f$ hides the enclosing one. So all references to $x$ inside $f$ refer to the inner declaration of $x$. However, many of these references are illegal, because they appear before the declaration. The assignment to $z$ is one such case. The assignment to $x$ in the \IF{} statement suffers from multiple problems. The right hand side reads $x$ before its declaration, and the left hand side assigns to $x$ before its declaration. Each of these are, independently, compile time errors. The print statement inside the \IF{} is also illegal.
The inner declaration of $x$ is itself erroneous because its right hand side attempts to read $x$ before the declaration has terminated. The left hand side is not, technically, a reference or an assignment but a declaration and so is legal. The last print statement is perfectly legal as well.
}
\commentary {
As another example \code{\VAR{} x = 3, y = x;} is legal, because \code{x} is referenced after its initializer.
A particularly perverse example involves a local variable name shadowing a type. This is possible because Dart has a single namespace for types, functions and variables.
}
\begin{dartCode}
\CLASS{} C \{\}
perverse() \{
\VAR{} v = \NEW{} C(); // compile-time error
C aC; // compile-time error
\VAR{} C = 10;
\}
\commentary {
Inside \cd{perverse()}, \cd{C} denotes a local variable. The type \cd{C} is hidden by the variable of the same name. The attempt to instantiate \cd{C} causes a compile-time error because it references a local variable prior to its declaration. Similarly, for the declaration of \cd{aC} (even though it is only a type annotation).
}
\rationale{
As a rule, type annotations are ignored in production mode. However, we do
not want to allow programs to compile legally in one mode and not another, and in this extremely odd situation, that consideration takes precedence.
}
\end{dartCode}
% the grammar does not support local getters and setters. The local var discussion does not seem to mention getters and setters based semantics. It simply discusses the creation of the variable, not its access. Access is either assignment or identifiers. Identifiers ignore the getter story.
\LMHash{}
The following rules apply to all static and instance variables.
\LMHash{}
A variable declaration of one of the forms \code{$T$ $v$;}, \code{$T$ $v$ = $e$;} , \code{\CONST{} $T$ $v$ = $e$;}, \code{\FINAL{} $T$ $v$;} or \code{\FINAL{} $T$ $v$ = $e$;} always induces an implicit getter function (\ref{getters}) with signature
$T$ \GET{} $v$
whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}).
\LMHash{}
A variable declaration of one of the forms \code{\VAR{} $v$;}, \code{\VAR{} $v$ = $e$;} , \code{\CONST{} $v$ = $e$;}, \code{\FINAL{} $v$;} or \code{\FINAL{} $v$ = $e$;} always induces an implicit getter function with signature
\GET{} $v$
whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}).
\LMHash{}
A non-final variable declaration of the form \code{{} $T$ $v$;} or the form \code{$T$ $v$ = $e$;} always induces an implicit setter function (\ref{setters}) with signature
\VOID{} \SET{} $v=(T$ $x)$
whose execution sets the value of $v$ to the incoming argument $x$.
\LMHash{}
A non-final variable declaration of the form \code{\VAR{} $v$;} or the form \code{\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$.
\subsection{Evaluation of Implicit Variable Getters}
\LMLabel{evaluationOfImplicitVariableGetters}
\LMHash{}
Let $d$ be the declaration of a static or instance variable $v$. If $d$ is an instance variable, then the invocation of the implicit getter of $v$ evaluates to the value stored in $v$.
If $d$ is a static or library variable then the implicit getter method of $v$ executes as follows:
\begin{itemize}
\item {\bf Non-constant variable declaration with initializer}. If $d$ is of one of the forms \code{\VAR{} $v$ = $e$;} , \code{$T$ $v$ = $e$;} , \code{\FINAL{} $v$ = $e$;} , \code{\FINAL{} $T$ $v$ = $e$;}, \code{\STATIC{} $v$ = $e$; }, \code{\STATIC{} $T$ $v$ = $e$; }, \code{\STATIC{} \FINAL{} $v$ = $e$; } or \code{\STATIC{} \FINAL{} $T$ $v$ = $e$;} and no value has yet been stored into $v$ then the initializer expression $e$ is evaluated. If, during the evaluation of $e$, the getter for $v$ is invoked, a \code{CyclicInitializationError} is thrown. If the evaluation succeeded yielding an object $o$, let $r = o$, otherwise let $r = \NULL{}$. In any case, $r$ is stored into $v$. The result of executing the getter is $r$.
\item {\bf Constant variable declaration}. If $d$ is of one of the forms \code{\CONST{} $v$ = $e$; } , \code{\CONST{} $T$ $v$ = $e$; }, \code{\STATIC{} \CONST{} $v$ = $e$; } or \code{\STATIC{} \CONST{} $T$ $v$ = $e$;} the result of the getter is the value of the compile time constant $e$. \commentary{Note that a compile time constant cannot depend on itself, so no cyclic references can occur.}
Otherwise
\item {\bf Variable declaration without initializer}. The result of executing the getter method is the value stored in $v$.
\end{itemize}
\section{Functions}
\LMLabel{functions}
\LMHash{}
Functions abstract over executable actions.
\begin{grammar}
{\bf functionSignature:}
metadata returnType? identifier formalParameterList
.
{\bf returnType:}
\VOID{};
type
.
{\bf functionBody:} \ASYNC{}? `={\escapegrammar \gt}' expression `{\escapegrammar ;}';
(\ASYNC{} $|$ \ASYNC* $|$ \SYNC*)? block
.
{\bf block:}
`\{' statements `\}'
.
\end{grammar}
\LMHash{}
Functions include function declarations (\ref{functionDeclarations}), methods (\ref{instanceMethods}, \ref{staticMethods}), getters (\ref{getters}), setters (\ref{setters}), constructors (\ref{constructors}) and function literals (\ref{functionExpressions}).
\LMHash{}
All functions have a signature and a body. The signature describes the formal parameters of the function, and possibly its name and return type. A function body is either:
\begin{itemize}
\item A block statement (\ref{blocks}) containing the statements (\ref{statements}) executed by the function, optionally marked with one of the modifiers: \ASYNC, \ASYNC* or \SYNC*. In this case, if the last statement of a function is not a return statement (\ref{return}), the statement \code{\RETURN{};} is implicitly appended to the function body.
\rationale{
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. A \RETURN{} without an expression returns \NULL{}. For generator functions, the situation is more subtle. See further discussion in section \ref{return}.
}
OR
\item of the form \code{=$>$ $e$} which is equivalent to a body of the form \code{\{\RETURN{} $e$;\}} or the form \code{\ASYNC{} =$>$ $e$} which is equivalent to a body of the form \code{\ASYNC{} \{\RETURN{} $e$;\}}. \rationale{The other modifiers do not apply here, because they apply only to generators, discussed below, and generators do not allow the form \code{\RETURN{} $e$}; values are added to the generated stream or iterable using \YIELD{} instead.}
\end{itemize}
\LMHash{}
A function is {\em asynchronous} if its body is marked with the \ASYNC{} or \ASYNC* modifier. Otherwise the function is {\em synchronous}. A function is a {\em generator} if its body is marked with the \SYNC* or \ASYNC* modifier.
\commentary{
Whether a function is synchronous or asynchronous is orthogonal to whether it is a generator or not. Generator functions are a sugar for functions that produce collections in a systematic way, by lazily applying a function that {\em generates} individual elements of a collection. Dart provides such a sugar in both the synchronous case, where one returns an iterable, and in the asynchronous case, where one returns a stream. Dart also allows both synchronous and asynchronous functions that produce a single value.
}
\LMHash{}
It is a compile-time error if an \ASYNC, \ASYNC* or \SYNC* modifier is attached to the body of a setter or constructor.
\rationale{
An asynchronous setter would be of little use, since setters can only be used in the context of an assignment (\ref{assignment}), and an assignment expression always evaluates to the value of the assignment's right hand side. If the setter actually did its work asynchronously, one might imagine that one would return a future that resolved to the assignment's right hand side after the setter did its work. However, this would require dynamic tests at every assignment, and so would be prohibitively expensive.
An asynchronous constructor would, by definition, never return an instance of the class it purports to construct, but instead return a future. Calling such a beast via \NEW{} would be very confusing. If you need to produce an object asynchronously, use a method.
One could allow modifiers for factories. A factory for \code{Future} could be modified by \ASYNC{}, a factory for \code{Stream} could be modified by \ASYNC* and a factory for \code{Iterable} could be modified by \SYNC*. No other scenario makes sense because the object returned by the factory would be of the wrong type. This situation is very unusual so it is not worth making an exception to the general rule for constructors in order to allow it.
}
\LMHash{}
It is a static warning if the declared return type of a function marked \ASYNC{} may not be assigned to \code{Future}. It is a static warning if the declared return type of a function marked \SYNC* may not be assigned to \code{Iterable}. It is a static warning if the declared return type of a function marked \ASYNC* may not be assigned to \code{Stream}.
\subsection{Function Declarations}
\LMLabel{functionDeclarations}
\LMHash{}
A {\em function declaration} is a function that is neither a member of a class nor a function literal. Function declarations include {\em library functions}, which are function declarations
%(including getters and setters)
at the top level of a library, and {\em local functions}, which are function declarations declared inside other functions. Library functions are often referred to simply as top-level functions.
\LMHash{}
A function declaration consists of an identifier indicating the function's name, possibly prefaced by a return type. The function name is followed by a signature and body. For getters, the signature is empty. The body is empty for functions that are external.
\LMHash{}
The scope of a library function is the scope of the enclosing library. The scope of a local function is described in section \ref{localFunctionDeclaration}. In both cases, the name of the function is in scope in its formal parameter scope (\ref{formalParameters}).
%A function declaration of the form $T_0$ $id(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])\{s\}$ is equivalent to a variable declaration of the form \code{\FINAL{} $F$ $id$ = $(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k}= d_k])\{s\}$}, where $F$ is the function type alias (\ref{typedef}) \code{\TYPEDEF{} $T_0$ $F(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}])$}. Likewise, a function declaration of the form $id(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])\{s\}$ is equivalent to a variable declaration of the form \code{\FINAL{} $F$ $id$ = $(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])\{s\}$}, where $F$ is the function type alias \code{\TYPEDEF{} $F(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}])$}.
%\Q{We need to cover library getters as well.}
%\Q{ The definition in terms of variables is untrue, because the code would be illegal. The initializer cannot refer to the function name in this case. I believe the best fix is to relax this
%requirement in the case of closures. See bug 315.
%}
%\commentary{
%Some obvious conclusions:
%A function declaration of the form $id(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k]) => e$ is equivalent to a variable declaration of the form \code{\FINAL{} $id$ = ($(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])=> e$}.
%A function literal of the form $(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k]) => e$ is equivalent to a function literal of the form \code{$(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])\{$ \RETURN{} $e$;\}}.
%}
%A function declaration of the form $T_0$ $id(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1} : d_1, \ldots, T_{n+k}$ $x_{n+k} : d_k\})\{s\}$ is equivalent to a variable declaration of the form \code{\FINAL{} $F$ $id$ = $(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1} : d_1, \ldots, T_{n+k}$ $x_{n+k} : d_k\})\{s\}$}, where $F$ is the function type alias (\ref{typedef}) \code{\TYPEDEF{} $T_0$ $F(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}]\}$}. Likewise, a function declaration of the form $id(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1} : d_1, \ldots, T_{n+k}$ $x_{n+k} : d_k\})\{s\}$ is equivalent to a variable declaration of the form \code{\FINAL{} $F$ $id$ = $(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1} : d_1, \ldots, T_{n+k}$ $x_{n+k} : d_k\})\{s\}$}, where $F$ is the function type alias \code{\TYPEDEF{} $F(T_1$ $a_1, \ldots, T_n$ $a_n, \{T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}\})$}.
\LMHash{}
It is a compile-time error to preface a function declaration with the built-in identifier \STATIC{}.
\LMHash{}
When we say that a function $f_1$ {\em forwards} to another function $f_2$, we mean that invoking $f_1$ causes $f_2$ to be executed with the same arguments and/or receiver as $f_1$, and returns the result of executing $f_2$ to the caller of $f_1$, unless $f_2$ throws an exception, in which case $f_1$ throws the same exception. Furthermore, we only use the term for synthetic functions introduced by the specification.
\subsection{Formal Parameters}
\LMLabel{formalParameters}
\LMHash{}
Every function includes a {\em formal parameter list}, which consists of a list of required positional parameters (\ref{requiredFormals}), followed by any optional parameters (\ref{optionalFormals}). The optional parameters may be specified either as a list of positional parameters, a set of named parameters, or both.
\LMHash{}
The formal parameter list of a function introduces a new scope known as the function's {\em formal parameter scope}. The formal parameter scope of a function $f$ is enclosed in the scope where $f$ is declared. Every formal parameter introduces a local variable into the formal parameter scope. However, the scope of a function's signature is the function's enclosing scope, not the formal parameter scope.
\LMHash{}
The body of a function introduces a new scope known as the function's {\em body scope}. The body scope of a function $f$ is enclosed in the scope introduced by the formal parameter scope of $f$.
%The formal parameter scope of a function maps the name of each formal parameter $p$ to the value $p$ is bound to.
% The formal parameters of a function are processed in the enclosing scope of the function.
% \commentary{this means that the parameters themselves may not be referenced within the formal parameter list.}
\LMHash{}
It is a compile-time error if a formal parameter is declared as a constant variable (\ref{variables}).
\begin{grammar}
{\bf formalParameterList:}`(' `)';
`(' normalFormalParameters ( `,' optionalFormalParameters)? `)';
`(' optionalFormalParameters `)'
.
%\end{grammar}
%}
%\begin{grammar}
%formalParameterList:
% '(' restFormalParameter? ')';
% '(' namedFormalParameters ')';
% '(' normalFormalParameters normalFormalParameterTail? ')'
% .
{\bf normalFormalParameters:}
normalFormalParameter (`,' normalFormalParameter)*
.
{\bf optionalFormalParameters:}
optionalPositionalFormalParameters (`,' namedFormalParameters)?;
namedFormalParameters;
.
{\bf optionalPositionalFormalParameters:}
`[' defaultFormalParameter (`,' defaultFormalParameter)* `]'
.
{\bf namedFormalParameters:}
`\{' defaultNamedParameter (`,' defaultNamedParameter)* `\}'
.
\end{grammar}
%Formal parameters are always \FINAL{}.
%\Q{We're awaiting some data on whether enforcing this would cause widespread pain.}
%A formal parameter is always considered to be initialized. \rationale{This is because it will always be initialized by the call - even if it is optional.}
\subsubsection{Required Formals}
\LMLabel{requiredFormals}
\LMHash{}
A {\em required formal parameter} may be specified in one of three ways:
\begin{itemize}
\item By means of a function signature that names the parameter and describes its type as a function type (\ref{functionTypes}). It is a compile-time error if any default values are specified in the signature of such a function type.% explain what the type is in this case? Where is this described in general?
\item As an initializing formal, which is only valid as a parameter to a generative constructor (\ref{generativeConstructors}). % do we need to say this, or anything more?
\item Via an ordinary variable declaration (\ref{variables}).
\end{itemize}
\begin{grammar}
{\bf normalFormalParameter:}functionSignature;
fieldFormalParameter;
simpleFormalParameter
.
{\bf simpleFormalParameter:}declaredIdentifier;
metadata identifier
.
{\bf fieldFormalParameter:}
metadata finalConstVarOrType? \THIS{} `{\escapegrammar .}' identifier formalParameterList?
.
\end{grammar}
%\subsubsection{Rest Formals}
%\LMLabel{restFormals}
%A rest formal $R$ must be the last parameter in a formal parameter list. If a type $T$ is specified for $R$, it signifies that the type of $R$ is $T[]$.
%\begin{grammar}
%restFormalParameter:
% finalConstVarOrType? '{\escapegrammar ...}' identifier
%\end{grammar}
\subsubsection{Optional Formals}
\LMLabel{optionalFormals}
\LMHash{}
Optional parameters may be specified and provided with default values.
\begin{grammar}
{\bf defaultFormalParameter:}
normalFormalParameter ('=' expression)?
.
{\bf defaultNamedParameter:}
normalFormalParameter ( `{\escapegrammar :}' expression)?
.
\end{grammar}
\LMHash{}
It is a compile-time error if the default value of an optional parameter is not a compile-time constant (\ref{constants}). If no default is explicitly specified for an optional parameter an implicit default of \NULL{} is provided.
\LMHash{}
It is a compile-time error if the name of a named optional parameter begins with an `\_' character.
\rationale{
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.
}
\subsection{Type of a Function}
\LMLabel{typeOfAFunction}
\LMHash{}
If a function does not declare a return type explicitly, its return type is \DYNAMIC{} (\ref{typeDynamic}), unless it is a constructor function, in which case its return type is the immediately enclosing class.
\LMHash{}
Let $F$ be a function with required formal parameters $T_1$ $p_1 \ldots, T_n$ $p_n$, return type $T_0$ and no optional parameters. Then the type of $F$ is $(T_1 ,\ldots, T_n) \rightarrow T_0$.
\LMHash{}
Let $F$ be a function with required formal parameters $T_1$ $p_1 \ldots, T_n$ $p_n$, return type $T_0$, positional optional parameters $T_{n+1}$ $p_{n+1}, \ldots, T_{n+k}$ $ p_{n+k}$ and no named optional parameters. Then the type of $F$ is $(T_1 ,\ldots, T_n, [T_{n+1}, \ldots, T_{n+k}]) \rightarrow T_0$.
\LMHash{}
Let $F$ be a function with required formal parameters $T_1$ $p_1 \ldots, T_n$ $p_n$, return type $T_0$, no positional optional parameters and named optional parameters $T_{n+1}$ $p_{n+1}, \ldots, T_{n+m}$ $ p_{n+m}$. Then the type of $F$ is $(T_1 ,\ldots, T_n, \{T_{n+1}$ $p_{n+1}, \ldots, T_{n+m}$ $p_{n+m}\}) \rightarrow T_0$.
\LMHash{}
Let $F$ be a function with required formal parameters $T_1$ $p_1 \ldots, T_n$ $p_n$, return type $T_0$, positional optional parameters $T_{n+1}$ $p_{n+1}, \ldots, T_{n+k}$ $ p_{n+k}$ and named optional parameters $T_{n+k+1}$ $p_{n+k+1}, \ldots, T_{n+k+m}$ $ p_{n+k+m}$. Then the type of $F$ is $(T_1 ,\ldots, T_n, [\{T_{n+1}, \ldots, T_{n+k}], \{T_{n+k+1}$ $p_{n+k+1}, \ldots, T_{n+k+m}$ $p_{n+k+m}\}) \rightarrow T_0$.
\LMHash{}
The run time type of a function object always implements the class \cd{Function}.
\commentary{
One cannot assume, based on the above, that given a function \cd{f}, \cd{f.runtimeType} will actually be \cd{Function}, or that any two distinct function objects necessarily have the same runtime type.
}
\rationale{
It is up to the implementation to choose an appropriate representation for functions.
For example, consider that a closure produced via property extraction treats equality different from ordinary closures, and is therefore likely a different class. Implementations may also use different classes for functions based on arity and or type. Arity may be implicitly affected by whether a function is an instance method (with an implicit receiver parameter) or not. The variations are manifold, and so this specification only guarantees that function objects are instances of some class that is considered to implement \cd{Function}.
}
\subsection{External Functions}
\LMLabel{externalFunctions}
\LMHash{}
An {\em external function} is a function whose body is provided separately from its declaration. An external function may be a top-level function (\ref{librariesAndScripts}), a method (\ref{instanceMethods}, \ref{staticMethods}), a getter (\ref{getters}), a setter (\ref{setters}) or a non-redirecting constructor (\ref{generativeConstructors}, \ref{factories}). External functions are introduced via the built-in identifier \EXTERNAL{} (\ref{identifierReference}) followed by the function signature.
\rationale{
External functions allow us to introduce type information for code that is not statically known to the Dart compiler.
}
\commentary{
Examples of external functions might be foreign functions (defined in C, or Javascript etc.), primitives of the implementation (as defined by the Dart runtime), or code that was dynamically generated but whose interface is statically known. However, an abstract method is different from an external function, as it has {\em no} body.
}
\LMHash{}
An external function is connected to its body by an implementation specific mechanism. Attempting to invoke an external function that has not been connected to its body will raise a \code{NoSuchMethodError} or some subclass thereof.
\LMHash{}
The actual syntax is given in sections \ref{classes} and \ref{librariesAndScripts} below.
\section{Classes}
\LMLabel{classes}
\LMHash{}
A {\em class} defines the form and behavior of a set of objects which are its {\em instances}. Classes may be defined by class declarations as described below, or via mixin applications (\ref{mixinApplication}).
\begin{grammar}
{\bf classDefinition:}
metadata \ABSTRACT{}? \CLASS{} identifier typeParameters? (superclass mixins?)? interfaces? \\
`\{' (metadata classMemberDefinition)* `\}';
metadata \ABSTRACT{}? \CLASS{} mixinApplicationClass
.
{\bf mixins:}
\WITH{} typeList
.
{\bf classMemberDefinition:}declaration `{\escapegrammar ;}' ;
methodSignature functionBody
.
{\bf methodSignature:}constructorSignature initializers?;
factoryConstructorSignature;
\STATIC{}? functionSignature;
\STATIC{}? getterSignature;
\STATIC{}? setterSignature;
operatorSignature
.
{\bf declaration:}constantConstructorSignature (redirection $|$ initializers)?;
constructorSignature (redirection $|$ initializers)?;
\EXTERNAL{} constantConstructorSignature;
\EXTERNAL{} constructorSignature;
((\EXTERNAL{} \STATIC{} ?))? getterSignature;
((\EXTERNAL{} \STATIC{}?))? setterSignature;
\EXTERNAL{}? operatorSignature;
((\EXTERNAL{} \STATIC{}?))? functionSignature;
\STATIC{} (\FINAL{} $|$ \CONST{}) type? staticFinalDeclarationList;
% \CONST{} type? staticFinalDeclarationList;
\FINAL{} type? initializedIdentifierList;
\STATIC{}? (\VAR{} $|$ type) initializedIdentifierList
.
{\bf staticFinalDeclarationList:}
staticFinalDeclaration (`,' staticFinalDeclaration)*
.
{\bf staticFinalDeclaration:}
identifier `=' expression
.
\end{grammar}
\LMHash{}
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. The members of a class are its static and instance members.
A class has several scopes:
\begin{itemize}
\item A {\em type-parameter scope}, which is empty if the class is not generic (\ref{generics}). The enclosing scope of the type-parameter scope of a class is the enclosing scope of the class declaration.
\item A {\em static scope}. The enclosing scope of the static scope of a class is the type parameter scope (\ref{generics}) of the class.
\item An {\em instance scope}.
The enclosing scope of a class' instance scope is the class' static scope.
\end{itemize}
The enclosing scope of an instance member declaration is the instance scope of the class in which it is declared.
The enclosing scope of a static member declaration is the static scope of the class in which it is declared.
\LMHash{}
Every class has a single superclass except class \code{Object} which has no superclass. A class may implement a number of interfaces
%, either
by declaring them in its implements clause (\ref{superinterfaces}).
% or via interface injection declarations (\ref{interfaceInjection}) outside the class declaration
\LMHash{}
An {\em abstract class} is
%either
a class that is explicitly declared with the \ABSTRACT{} modifier, either by means of a class declaration or via a type alias (\ref{typedef}) for a mixin application (\ref{mixinApplication}). A {\em concrete class} is a class that is not abstract.
%, or a class that declares at least one abstract method (\ref{abstractInstanceMembers}).
\rationale{
%The abstract modifier for classes 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, w
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.
}
\LMHash{}
The {\em 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$ (\ref{superinterfaces}). When a class name appears as a type, that name denotes the interface of the class.
% making an exception for the setters generated for final fields is tempting but problematic.
% If a super type defines a setter, it will be overridden yet have no impact on the interface.
% Maybe the final field hides the setter in scope?
% I think the original rules were best.
\LMHash{}
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.
It is a compile-time error if a class has an instance member and a static member with the same name.
% It is a compile-time error if a generic (\ref{generics}) class declares a member with the same name as one of its type parameters.
\commentary{Here are simple examples, that illustrate the difference between ``has a member'' and ``declares a member''. For example, \code{B} {\em declares} one member named \code{f}, but {\em has} two such members. The rules of inheritance determine what members a class has.
}
\begin{dartCode}
\CLASS{} A \{
\VAR{} i = 0;
\VAR{} j;
f(x) =$>$ 3;
\}
\CLASS{} B \EXTENDS{} A \{
int i = 1; // getter i and setter i= override versions from A
\STATIC{} j; // compile-time error: static getter \& setter conflict with
//instance getter \& setter
/* compile-time error: static method conflicts with instance method */
\STATIC{} f(x) =$>$ 3;
\}
\end{dartCode}
\LMHash{}
It is a compile time error if a class $C$ declares a member with the same name as $C$. It is a compile time error if a generic class declares a type variable with the same name as the class or any of its members or constructors.
\subsection{Instance Methods}
\LMLabel{instanceMethods}
\LMHash{}
Instance methods are functions (\ref{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.
%make these warnings if possible
\LMHash{}
It is a static warning if an instance method $m_1$ overrides (\ref{inheritanceAndOverriding}) an instance member $m_2$ and $m_1$ has a greater number of required parameters than $m_2$. It is a static warning if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ has fewer positional parameters than $m_2$. It is a static warning if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ does not declare all the named parameters declared by $m_2$.
% not quite right. It should be ok to override a method that requires N parameters with one that requires M < N but accepts the others as optional.
\LMHash{}
It is a static warning if an instance method $m_1$ overrides an instance member $m_2$ and the type of $m_1$ is not a subtype of the type of $m_2$. It is a static warning if an instance method $m_1$ overrides an instance member $m_2$, the signature of $m_2$ explicitly specifies a default value for a formal parameter $p$ and the signature of $m_1$ implies a different default value for $p$. It is a static warning if a class $C$ declares an instance method named $n$ and has a setter named $n=$. It is a static warning if a class $C$ declares an instance method named $n$ and an accessible static member named $n$ is declared in a superclass of $C$.
% Works. If the name is public, no issue. If it's private, if a subclass has a conflicting inst var, it either is in the same lib and will be flagged, or is in another and is not an issue.
\subsubsection{Operators}
\LMLabel{operators}
\LMHash{}
{\em Operators} are instance methods with special names.
\begin{grammar}
{\bf operatorSignature:}
returnType? \OPERATOR{} operator formalParameterList
.
{\bf operator:}`\~{}';
binaryOperator;
`[' `]' ;
`[' `]' `='
.
{\bf binaryOperator:}multiplicativeOperator;
additiveOperator;
shiftOperator;
relationalOperator;
`==';
bitwiseOperator
.
\end{grammar}
\LMHash{}
An operator declaration is identified using the built-in identifier (\ref{identifierReference}) \OPERATOR{}.
\LMHash{}
The following names are allowed for user-defined operators: \code{$<$, $>$, $<$=, $>$=, ==, -, +, /, \~{}/, *, \%, $|$, \^{}, \&, $<<$, $>>$, []=, [], \~{}.}
\LMHash{}
It is a compile-time error if the arity of the user-declared operator \code{[]=} is not 2. It is a compile-time error if the arity of a user-declared operator with one of the names: \code{ $<$, $>$, $<$=, $>$=, ==, -, +, \~{}/, /, *, \%, $|$, \^{}, \&, $<<$, $>>$, []} is not 1. It is a compile-time error if the arity of the user-declared operator \code{-} is not 0 or 1.
\commentary{
The \code{-} operator is unique in that two overloaded versions are permitted. If the operator has no arguments, it denotes unary minus. If it has an argument, it denotes binary subtraction.
}
\LMHash{}
The name of the unary operator \code{-} is \code{unary-}.
\rationale{
This device allows the two methods to be distinguished for purposes of method lookup, override and reflection.
}
\LMHash{}
It is a compile-time error if the arity of the user-declared operator \code{ \~{}} is not 0.