From 642f8d052fd7fda51651b38bb77f59713de74ac3 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 19 Dec 2019 08:57:10 +0000 Subject: [PATCH] Remove dartLangSpec.tex; current version is in language repo Change-Id: Ic2838a26fbba85b14afc8a0131386fe83195c176 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/128881 Reviewed-by: Leaf Petersen Commit-Queue: Erik Ernst --- docs/language/Makefile | 45 - docs/language/dart.sty | 348 - docs/language/dartLangSpec.tex | 16388 ------------------------------- 3 files changed, 16781 deletions(-) delete mode 100644 docs/language/Makefile delete mode 100644 docs/language/dart.sty delete mode 100644 docs/language/dartLangSpec.tex diff --git a/docs/language/Makefile b/docs/language/Makefile deleted file mode 100644 index 1bdd95ac13f..00000000000 --- a/docs/language/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -NAME=dartLangSpec -SPEC=$(NAME).tex -HASH=$(NAME)-hash.tex -LIST=$(NAME)-list.txt -HASHER=../../tools/addlatexhash.dart - -pdf: - pdflatex $(SPEC) - makeindex $(NAME).idx - pdflatex $(SPEC) - pdflatex $(SPEC) - -pdfhash: hash_and_list - pdflatex $(HASH) - makeindex $(NAME)-hash.idx - pdflatex $(HASH) - pdflatex $(HASH) - -dvi: - latex $(SPEC) - makeindex $(NAME).idx - latex $(SPEC) - latex $(SPEC) - -dvihash: hash_and_list - latex $(HASH) - makeindex $(NAME)-hash.idx - latex $(HASH) - latex $(HASH) - -hash_and_list: - dart $(HASHER) $(SPEC) $(HASH) $(LIST) - -help: - @echo "Goals:" - @echo " pdf, dvi: generate the pdf/dvi file containing the spec" - @echo " pdfhash, dvihash: ditto, with location markers filled in" - @echo " cleanish: remove [pdf]latex generated intermediate files" - @echo " clean: remove all generated files" - -cleanish: - rm -f *.aux *.log *.toc *.out - -clean: cleanish - rm -f *.dvi *.pdf $(HASH) $(LIST) diff --git a/docs/language/dart.sty b/docs/language/dart.sty deleted file mode 100644 index 77d8efa2bb0..00000000000 --- a/docs/language/dart.sty +++ /dev/null @@ -1,348 +0,0 @@ -\def\builtinId#1{\textsf{\textbf{#1}}} -\def\keyword#1{\textsf{\textbf{#1}}} -\def\metavar#1{\ensuremath{\mathit{#1}}} - -\def\ABSTRACT{\builtinId{abstract}} -\def\AS{\builtinId{as}} -\def\COVARIANT{\builtinId{covariant}} -\def\DEFERRED{\builtinId{deferred}} -\def\DYNAMIC{\builtinId{dynamic}} -\def\EXPORT{\builtinId{export}} -\def\EXTERNAL{\builtinId{external}} -\def\FACTORY{\builtinId{factory}} -\def\FUNCTION{\builtinId{Function}} -\def\GET{\builtinId{get}} -\def\IMPLEMENTS{\builtinId{implements}} -\def\IMPORT{\builtinId{import}} -\def\INTERFACE{\builtinId{interface}} -\def\LIBRARY{\builtinId{library}} -\def\MIXIN{\builtinId{mixin}} -\def\OPERATOR{\builtinId{operator}} -\def\PART{\builtinId{part}} -\def\SET{\builtinId{set}} -\def\STATIC{\builtinId{static}} -\def\TYPEDEF{\builtinId{typedef}} - -\def\ASSERT{\keyword{assert}} -\def\ASYNC{\keyword{async}} -\def\AWAIT{\keyword{await}} -\def\BREAK{\keyword{break}} -\def\CASE{\keyword{case}} -\def\CATCH{\keyword{catch}} -\def\CLASS{\keyword{class}} -\def\CONST{\keyword{const}} -\def\CONTINUE{\keyword{continue}} -\def\DEFAULT{\keyword{default}} -\def\DO{\keyword{do}} -\def\ELSE{\keyword{else}} -\def\ENUM{\keyword{enum}} -\def\EXTENDS{\keyword{extends}} -\def\FALSE{\keyword{false}} -\def\FINAL{\keyword{final}} -\def\FINALLY{\keyword{finally}} -\def\FOR{\keyword{for}} -\def\HIDE{\keyword{hide}} -\def\IF{\keyword{if}} -\def\IN{\keyword{in}} -\def\IS{\keyword{is}} -\def\NEW{\keyword{new}} -\def\NULL{\keyword{null}} -\def\OF{\keyword{of}} -\def\ON{\keyword{on}} -\def\RETHROW{\keyword{rethrow}} -\def\RETURN{\keyword{return}} -\def\SHOW{\keyword{show}} -\def\SUPER{\keyword{super}} -\def\SWITCH{\keyword{switch}} -\def\SYNC{\keyword{sync}} -\def\THIS{\keyword{this}} -\def\THROW{\keyword{throw}} -\def\TRUE{\keyword{true}} -\def\TRY{\keyword{try}} -\def\VAR{\keyword{var}} -\def\VOID{\keyword{void}} -\def\WHILE{\keyword{while}} -\def\WITH{\keyword{with}} -\def\YIELD{\keyword{yield}} - -% Used for inline code snippets. -\def\code#1{\texttt{#1}} - -% `call` has no special lexical status, so we just use \code{}. -\def\CALL{\code{call}} - -% Define commands for `<<`, `>>`, `>>>` that avoid introducing guillemets. -\def\ltlt{<\mbox <} -\def\gtgt{>\mbox >} -\def\gtgtgt{>\mbox >\mbox >} - -% Used as line break in the right hand side of a grammar -% alternative, that is, when starting a "continuation line". -\newcommand{\gnewline}{\leavevmode\\} - -% Metavariables for argument lists. -\newcommand{\argumentList}[1]{\metavar{{#1}s}} -\newcommand{\parameterList}[1]{\metavar{{#1}s}} - -% Colors used for for different kinds of text. -\definecolor{normativeColor}{rgb}{0,0,0} -\definecolor{commentaryColor}{rgb}{0.5,0.5,0.5} -\definecolor{rationaleColor}{rgb}{0.5,0.5,0.5} - -% Environments for different kinds of text. -\newenvironment{Q}[1]{{\bf{}Upcoming: {#1}}}{} -\newenvironment{rationale}[1]{{\color{rationaleColor}\it{#1}}}{} -\newenvironment{commentary}[1]{{\color{commentaryColor}\sf{#1}}}{} - -% Auxiliary functions. -\newcommand{\flatten}[1]{\ensuremath{\mbox{\it flatten}({#1})}} -\newcommand{\futureOrBase}[1]{\ensuremath{\mbox{\it futureOrBase}({#1})}} -\newcommand{\overrides}[1]{\ensuremath{\mbox{\it overrides}({#1})}} -\newcommand{\inherited}[1]{\ensuremath{\mbox{\it inherited}({#1})}} - -% Used as a mini-section marker, indicating visibly that a range of -% text (usually just a couple of paragraphs) are concerned with one -% specific topic in a list of similar topics (like many forms of -% expressions of a similar nature). -\newcommand{\Case}[1]{\textbf{Case }$\langle\hspace{0.1em}${#1}$\hspace{0.1em}\rangle$\textbf{.}} -\newcommand{\EndCase}{\mbox{}\hfill$\scriptscriptstyle\Box$\xspace} - -\newenvironment{dartCode}[1][!ht] {% - \def\@programcr{\@addfield\strut}% - \let\\=\@programcr% - \relax\@vobeyspaces\obeylines% - \ttfamily\color{commentaryColor}% - \vspace{1em}% -}{\normalcolor\vspace{1em}} - -\newenvironment{normativeDartCode}[1][!ht] {% - \def\@programcr{\@addfield\strut}% - \let\\=\@programcr% - \relax\@vobeyspaces\obeylines% - \ttfamily\color{normativeColor}% - \vspace{1em}% -}{\normalcolor\vspace{1em}} - -% Used for comments in a code context. -\def\comment#1{\textsf{#1}} - -% A commonly used metavariable for an identifier, operator. -\newcommand{\id}{\metavar{id}} -\newcommand{\op}{\metavar{op}} - -% Used for defining occurrence of phrase, with customized index entry. -\newcommand{\IndexCustom}[2]{% - \leavevmode\marginpar{\ensuremath{\diamond}}\emph{#1}\index{#2}} - -% Used when one concept should have >1 entry in the index. Does not add -% the diamond in the margin and shows no text where the command occurs. -% Intended to be used immediately after another \Index... command. -\newcommand{\IndexExtraEntry}[1]{\index{#1}} - -% Used for a defining occurrence of a phrase, adding it to the index. -\newcommand{\Index}[1]{\IndexCustom{#1}{#1}} - -% Same appearance, but not adding an entry to the index. -\newcommand{\NoIndex}[1]{% - \leavevmode\marginpar{\ensuremath{\diamond}}\emph{#1}} - -% Used to specify comma separated lists of similar symbols. -\newcommand{\List}[3]{\ensuremath{{#1}_{#2},\,\ldots,\ {#1}_{#3}}} - -% Used to specify comma separated lists of pairs of similar symbols, -% as needed, e.g., for declarations of formal parameters. -% Parameters: Name of first part of pair, name of second part, -% index at start, index at end. -\newcommand{\PairList}[4]{\ensuremath{% - {#1}_{#3}\ {#2}_{#3},\,\ldots,\ {#1}_{#4}\ {#2}_{#4}}} - -% Used to specify comma separated lists of triples of similar symbols, -% as needed, e.g., for declarations of formal parameters with defaults. -% Parameters: Name of first part of triple, name of second part, -% name of third part, index at start, index at end. -\newcommand{\TripleList}[5]{\ensuremath{% - {#1}_{#4}\ {#2}_{#4}\ {#3}_{#4},\,\ldots,\ {#1}_{#5}\ {#2}_{#5}\ {#3}_{#5}}} - -% Used to abbreviate \EXTENDS{} in function types. -\newcommand{\FunctionTypeExtends}{\ensuremath{\triangleleft}} - -% Used to specify comma separated lists of pairs of symbols -% separated by \EXTENDS{}, as needed for type parameter declarations. -% Parameters: Type parameter name, bound name, number of type parameters. -\newcommand{\TypeParameters}[3]{\ensuremath{% - {#1}_1\,\EXTENDS\,{#2}_1,\,\ldots,\ % - {#1}_{#3}\,\EXTENDS\,{#2}_{#3}}} - -% Used to specify comma separated lists of symbols followed by -% \EXTENDS{}, as needed for type parameter declarations where we do -% not intend to refer explicitly to the bounds. -% Parameters: Type parameter name, number of type parameters. -\newcommand{\TypeParametersNoBounds}[2]{\ensuremath{% - {#1}_1\,\EXTENDS\,\ldots,\ \ldots,\ {#1}_{#2}\,\EXTENDS\,\ldots}} - -% For consistency, we may as well use this whenever possible. -\newcommand{\TypeParametersStd}{\TypeParameters{X}{B}{s}} - -% Used to specify comma separated lists of pairs of symbols -% separated by \EXTENDS{}, as needed for type parameter declarations. -% Parameters: Type parameter name, bound name, number of type parameters. -\newcommand{\FTTypeParameters}[3]{\ensuremath{% - {#1}_1\FunctionTypeExtends{#2}_1,\,\ldots,\ % - {#1}_{#3}\FunctionTypeExtends{#2}_{#3}}} - -% Used to specify simple non-generic function types: Same syntax as in source. -% Arguments: Return type, formal parameter declarations. -\newcommand{\FunctionTypeSimple}[2]{\code{\ensuremath{#1}\ \FUNCTION({#2})}} - -% Used to specify simple generic function types: Same syntax as in source. -% Arguments: Return type, formal parameter declarations. -\newcommand{\FunctionTypeSimpleGeneric}[3]{\code{% - \ensuremath{#1}\ \FUNCTION<{#2}>({#3})}} - -% Used to specify function types: Same syntax as in source. -% Arguments: Return type, spacer, type parameter name, bound name, -% number of type parameters, formal parameter declarations. -\newcommand{\FunctionType}[6]{\leavevmode\par\noindent\code{% - \ensuremath{#1}{#2}\FUNCTION<\FTTypeParameters{#3}{#4}{#5}>({#6})}} - -% Same as \FunctionType except suitable for inline usage, hence omitting -% the spacer argument. -\newcommand{\RawFunctionType}[5]{\code{% - \ensuremath{#1}\ \FUNCTION<\FTTypeParameters{#2}{#3}{#4}>({#5})}} - -% Used to specify function type parameter lists with positional optionals. -% Arguments: Parameter type, number of required parameters, -% number of optional parameters. -\newcommand{\FunctionTypePositionalArguments}[3]{% - \List{#1}{1}{#2},\ [\List{#1}{{#2}+1}{{#2}+{#3}}]} - -\newcommand{\FunctionTypePositionalArgumentsStd}{% - \FunctionTypePositionalArguments{T}{n}{k}} - -% Used to specify function types with positional optionals: -% Arguments: Return type, spacer, type parameter name, bound name, -% number of type parameters, parameter type, number of required parameters, -% number of optional parameters. -\newcommand{\FunctionTypePositional}[8]{% - \FunctionType{#1}{#2}{#3}{#4}{#5}{% - \FunctionTypePositionalArguments{#6}{#7}{#8}}} - -% Same as \FunctionTypePositional except suitable for inline usage, -% hence omitting the spacer argument. -\newcommand{\RawFunctionTypePositional}[7]{% - \RawFunctionType{#1}{#2}{#3}{#4}{% - \FunctionTypePositionalArguments{#5}{#6}{#7}}} - -% Used to specify function type parameter lists with named optionals. -% Arguments: Parameter type, number of required parameters, -% name of optional parameters, number of optional parameters. -\newcommand{\FunctionTypeNamedArguments}[4]{% - \List{#1}{1}{#2},\ \{\PairList{#1}{#3}{{#2}+1}{{#2}+{#4}}\}} - -\newcommand{\FunctionTypeNamedArgumentsStd}{% - \FunctionTypeNamedArguments{T}{n}{x}{k}} - -% Used to specify function types with named parameters: -% Arguments: Return type, spacer, type parameter name, bound name, -% number of type parameters, parameter type, number of required parameters, -% name of optional parameters, number of optional parameters. -\newcommand{\FunctionTypeNamed}[9]{% - \FunctionType{#1}{#2}{#3}{#4}{#5}{% - \FunctionTypeNamedArguments{#6}{#7}{#8}{#9}}} - -% Same as \FunctionType except suitable for inline usage, hence omitting -% the spacer argument. -\newcommand{\RawFunctionTypeNamed}[8]{% - \RawFunctionType{#1}{#2}{#3}{#4}{% - \FunctionTypeNamedArguments{#5}{#6}{#7}{#8}}} - -% Used to specify function types with no optional parameters: -% Arguments: Return type, spacer, type parameter name, bound name, -% number of type parameters, parameter type, -% number of parameters (all required). -\newcommand{\FunctionTypeAllRequired}[7]{% - \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7}}} - -\newcommand{\FunctionTypePositionalStd}[1]{% - \FunctionTypePositional{#1}{ }{X}{B}{s}{T}{n}{k}} - -\newcommand{\RawFunctionTypePositionalStd}[1]{% - \RawFunctionTypePositional{#1}{X}{B}{s}{T}{n}{k}} - -\newcommand{\FunctionTypeNamedStd}[1]{% - \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}} - -\newcommand{\RawFunctionTypeNamedStd}[1]{% - \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}} - -\newcommand{\FunctionTypeAllRequiredStd}[1]{% - \FunctionTypeAllRequired{#1}{ }{X}{B}{s}{T}{n}} - -\newcommand{\FunctionTypePositionalStdCr}[1]{% - \FunctionTypePositional{#1}{\\}{X}{B}{s}{T}{n}{k}} - -\newcommand{\FunctionTypeNamedStdCr}[1]{% - \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}} - -\newcommand{\FunctionTypeAllRequiredStdCr}[1]{% - \FunctionTypeAllRequired{#1}{\\}{X}{B}{s}{T}{n}} - -\newcommand{\MoreSignatureSpecificSymbol}{\ensuremath{\preceq}} -\newcommand{\NotMoreSignatureSpecificSymbol}{\ensuremath{\not\preceq}} -\newcommand{\LessSignatureSpecificSymbol}{\ensuremath{\succeq}} - -\newcommand{\MoreSignatureSpecific}[2]{% - \ensuremath{{#1}\MoreSignatureSpecificSymbol{#2}}} -\newcommand{\NotMoreSignatureSpecific}[2]{% - \ensuremath{{#1}\NotMoreSignatureSpecificSymbol{#2}}} - -% Judgment expressing that a subtype relation exists. -\newcommand{\Subtype}[3]{\ensuremath{{#1}\vdash{#2}\,<:\,{#3}}} -\newcommand{\SubtypeStd}[2]{\Subtype{\Gamma}{#1}{#2}} -% Subtype judgment where the environment is omitted (NE: "no environment"). -\newcommand{\SubtypeNE}[2]{\ensuremath{{#1}\,<:\,{#2}}} - -% Judgment expressing that a supertype relation exists. -\newcommand{\Supertype}[3]{\ensuremath{{#1}\vdash{#2}\,:>\,{#3}}} -\newcommand{\SupertypeStd}[2]{\Supertype{\Gamma}{#1}{#2}} - -% Judgment expressing that an assignability relation exists. -\newcommand{\AssignableRelationSymbol}{\ensuremath{\Longleftrightarrow}} -\newcommand{\Assignable}[3]{% - \ensuremath{{#1}\vdash{#2}\,\AssignableRelationSymbol\,{#3}}} -\newcommand{\AssignableStd}[2]{\Assignable{\Gamma}{#1}{#2}} - -% Semantic function delivering the superinterfaces of a class. -\newcommand{\Superinterfaces}[1]{\ensuremath{\metavar{Superinterfaces}({#1})}} -\newcommand{\Superinterface}[2]{{#1}\in\Superinterfaces{#2}} - -% ---------------------------------------------------------------------- -% Support for hash valued Location Markers - -% very small font, to enable 40 char hash values in the margin -\makeatletter -\ifcase \@ptsize \relax% 10pt - \newcommand{\miniscule}{\@setfontsize\miniscule{2}{3}}% \tiny: 5/6 -\or% 11pt - \newcommand{\miniscule}{\@setfontsize\miniscule{3}{4}}% \tiny: 6/7 -\or% 12pt - \newcommand{\miniscule}{\@setfontsize\miniscule{3}{4}}% \tiny: 6/7 -\fi -\makeatother - -% white: location markers should not create visual noise -\definecolor{LMdim}{gray}{1.0} - -% insert location marker showing hash value of following paragraph -\newcommand{\LMHash}[1]{\leavevmode\marginpar{\quad% - \raisebox{0.5ex}{\miniscule{\color{LMdim}#1}}\vspace{-2\baselineskip}}% - \color{normativeColor}} - -% support convenient renewcommand -\let\OriginalLMHash\LMHash - -% define a label, and show the associated logical location marker -\newcommand{\LMLabel}[1]{% - \vspace{-\baselineskip}\leavevmode\OriginalLMHash{\raisebox{10ex}{#1}}% - \label{#1}} -% ---------------------------------------------------------------------- diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex deleted file mode 100644 index 6cb53ccfdaa..00000000000 --- a/docs/language/dartLangSpec.tex +++ /dev/null @@ -1,16388 +0,0 @@ -\documentclass[makeidx]{article} -\usepackage{xspace} -\usepackage{epsfig} -\usepackage{xcolor} -\usepackage{syntax} -\usepackage{amssymb} -\usepackage[fleqn]{amsmath} -\usepackage{amssymb} -\usepackage{semantic} -\usepackage{dart} -\usepackage{hyperref} -\usepackage{lmodern} -\usepackage[T1]{fontenc} -\usepackage{makeidx} -\makeindex -\title{Dart Programming Language Specification\\ -{5th edition draft}\\ -{\large Version 2.2.0-dev}} -\author{} - -% For information about Location Markers (and in particular the -% commands \LMHash and \LMLabel), see the long comment at the -% end of this file. - -% CHANGES -% ======= -% Significant changes to the specification. -% 2.2 -% - Specify whether the values of literal expressions override Object.==. -% - Allow Type objects as case expressions and const map keys. -% - Introduce set literals. -% - Specify that a getter/setter and a method with the same basename is -% an error, also in the case where a class obtains both from its -% superinterfaces. -% - Specify the Dart 2.0 rule that you cannot implement, extend or mix-in -% Function. -% - Generalize specification of type aliases such that they can denote any -% type, not just function types. -% -% 2.1 -% - Remove 64-bit constraint on integer literals compiled to JavaScript numbers. -% - Allow integer literals in a double context to evaluate to a double value. -% - Specify dynamic error for a failing downcast in redirecting factory -% constructor invocation. -% - Specify that type arguments passed in a redirecting factory constructor -% declaration must be taken into account during static checks. -% - Disallow any expression statement starting with `{`, not just -% those that are map literals. -% - Define a notion of lookup that is needed for super invocations, adjust -% specification of super invocations accordingly. -% - Specify that it is a dynamic error to initialize a non-static variable -% with a value that does not have the declared type (e.g., a failed cast). -% - Specify for constructor initializers that target variable must exist and -% the initializing expression must have a type which is assignable to its -% type. -% - Specify for superinitializers that the target constructor must exist and -% the argument part must have a matching shape and pass type and value -% arguments satisfying the relevant constraints. -% - Reword rules about abstract methods and inheritance to use 'class -% interface'. -% - Specify that it is an error for a concrete class with no non-trivial -% \code{noSuchMethod} to not have a concrete declaration for some member -% in its interface, or to have one which is not a correct override. -% - Use \ref{bindingActualsToFormals} in 3 locations, eliminating 2 extra -% copies of nearly the same text. -% - Add figure in \ref{bindingActualsToFormals} for improved readability. -% - Introduce a notion of lookup which is needed for superinvocations. -% - Use new lookup concept to simplify specification of getter, setter, method -% lookup. -% - Introduce several `Case` markers in order to improve -% readability. -% - Reorganize several sections to specify static analysis first and then -% dynamic semantics; clarify many details along the way. The sections are: -% \ref{variables}, \ref{new}, \ref{const}, \ref{bindingActualsToFormals}, -% \ref{unqualifiedInvocation}, \ref{functionExpressionInvocation}, -% \ref{superInvocations}, \ref{assignment}, \ref{compoundAssignment}, -% \ref{localVariableDeclaration}, and \ref{return}. -% - Corrected error involving multiple uses of the same part in the same -% program such that it takes exports into account. -% - Eliminate all references to checked and production mode, Dart 2 does -% not have modes. -% - Integrate feature specification on noSuchMethod forwarders. -% - Specify that bound satisfaction in generic type alias type parameters -% must imply bound satisfaction everywhere in the body. -% - Specify that super-bounded generic type alias applications must trigger -% a well-boundedness check on all types occurring in the denoted type. -% - Corrected corner case of rules for generation of noSuchMethod forwarders. -% - Integrate feature specification on parameters that are -% covariant-by-declaration. -% - Integrate feature specification on parameters that are -% covariant-by-class. -% - Correct section 'Type of a function', allowing for adjustments needed -% for rules related to covariant parameters. -% - Specified the dynamic type of function objects in several contexts, such -% that the special treatment of covariant parameters can be mentioned. -% - Specified what it means for an override relation to be correct, thus -% adding the parts that are not captured by a function type subtype check. -% - Introduced the notion of member signatures, specified that they are the -% kind of entity that a class interface contains. -% - Corrected super-boundedness check to take variance into account at the -% top level. -% -% 2.0 -% - Don't allow functions as assert test values. -% - Start running "async" functions synchronously. -% - It is a static warning and dynamic error to assign to a final local. -% - Specify what "is equivalent to" means. -% - Remove @proxy. -% - Don't specify the exact object used for empty positionalArguments and -% namedArguments on Invocation. -% - Remove the, now unnecessary, handling of invalid overrides of noSuchMethod. -% - Add >>> as overridable operator. -% - If initializing formal has type annotation, require subtype of field type. -% - Constant `==` operations now also allowed if just one operand is null. -% - Make flatten not be recursive. -% - Disallow implementing two instantiations of the same generic interface. -% - Update "FutureOr" specification for Dart 2.0. -% - Require that a top-level "main" declaration is a valid script-entry -% function declaration. -% - State that the return type of a setter or []= is void when not specified. -% - Clarify that "noSuchMethod" must be implemented, not just redeclared -% abstractly, to eliminate certain diagnostic messages. -% - Add generic functions and methods to the language. -% - Don't cause warning if a non-system library import shadows a system library. -% - Update mixin application forwarding constructors to correctly handle -% optional parameters and const constructors. -% - Specify `call` for Dart 2 (no function type given to enclosing class). -% - Clarify that an identifier reference denoting a top-level, static, or -% local function evaluates to the closurization of that declaration. -% - Make `mixin` and `interface` built-in identifiers. -% - Make `async` *not* a reserved word inside async functions. -% - Add 'Class Member Conflicts', simplifying and adjusting rules about -% member declaration conflicts beyond "`n` declared twice in one scope". -% - Specify that integer literals are limited to signed 64-bit values, -% and that the `int` class is intended as signed 64-bit integer, but -% that platforms may differ. -% - Specify variance and super-bounded types. -% - Introduce `subterm` and `immediate subterm`. -% - Introduce `top type`. -% - Specify configurable imports. -% - Specify the dynamic type of the Iterable/Future/Stream returned from -% invocations of functions marked sync*/async/async*. -% - Add appendix listing the major differences between 64-bit integers -% and JavaScript integers. -% - Remove appendix on naming conventions. -% - Make it explicit that "dynamic" is exported from dart:core. -% - Remove "boolean conversion". It's just an error to not be a bool. -% - Adjust cyclic subtype prevention rule for type variables. -% - Clarify that it is an error to use FutureOr as a superinterface etc. -% - Eliminate the notion of static warnings, all program faults are now errors. -% - It is no longer an error for a getter to have return type `void`. -% - Specify that each redirection of a constructor is checked, statically and -% dynamically. -% - Specify that it is an error for a superinitializer to occur anywhere else -% than at the end of an initializer list. -% - Update the potentially/compile-time constant expression definitions -% so that "potentially constant" depends only on the grammar, not the types -% of sub-expressions. -% - Make `==` recognize `null` and make `&&` and `||` short-circuit in constant -% expressions. -% - Add `as` and `is` expressions as constant expressions -% - Make `^`, `|` and `&` operations on `bool` constant operations. -% - Integrate subtyping.md. This introduces the Dart 2 rules for subtyping, -% which in particular means that the notion of being a more specific type -% is eliminated, and function types are made contravariant in their -% parameter types. -% - Integrate instantiation to bound. This introduces the notions of raw -% types, the raw-depends relation, and simple bounds; and it specifies -% the algorithm which is used to expand a raw type (e.g., `C`) to a -% parameterized type (e.g., `C`). -% - Integrate invalid_returns.md. This replaces the rules about when it is -% an error to have `return;` or `return e;` in a function. -% - Integrate generalized-void.md. Introduces syntactic support for using -% `void` in many new locations, including variable type annotations and -% actual type arguments; also adds errors for using values of type `void`. -% - Integrate implicit_creation.md, specifying how some constant expressions -% can be written without `const`, and all occurrences of `new` can be -% omitted. -% -% 1.15 -% - Change how language specification describes control flow. -% - Object initialization now specifies initialization order correctly. -% - Specifies that leaving an await-for loop must wait for the subscription -% to be canceled. -% - An await-for loop only pauses the subscription if it does something async. -% - Assert statements allows a "message" operand and a trailing comma. -% - The Null type is now considered a subtype of all types in most cases. -% - Specify what NEWLINE means in multiline strings. -% - Specified the FutureOf type. -% - Asserts can occur in initializer lists. -% -% 1.14 -% - The call "C()" where "C" is a class name, is a now compile-time error. -% - Changed description of rewrites that depended on a function literal. -% In many cases, the rewrite wasn't safe for asynchronous code. -% - Removed generalized tear-offs. -% - Allow "rethrow" to also end a switch case. Allow braces around switch cases. -% - Allow using '=' as default-value separator for named parameters. -% - Make it a compile-time error if a library includes the same part twice. -% - Now more specific about the return types of sync*/async/async* functions -% in relation to return statements. -% - Allow Unicode surrogate values in String literals. -% - Make an initializing formal's value accessible in the initializer list. -% - Allow any expression in assert statements (was only conditionalExpression). -% - Allow trailing commas in argument and parameter lists. -% -% 1.11 - ECMA 408 - 4th Edition -% - Specify that potentially constant expressions must be valid expressions -% if the parameters are non-constant. -% - Make "??" a compile-time constant operator. -% - Having multiple unnamed libraries no longer causes warnings. -% - Specify null-aware operators for static methods. -% -% 1.10 -% - Allow mixins to have super-classes and super-calls. -% - Specify static type checking for the implicit for-in iterator variable. -% - Specify static types for a number of expressions where it was missing. -% - Make calls on the exact type "Function" not cause warnings. -% - Specify null-aware behavior of "e?.v++" and similar expressions. -% - Specify that `package:` URIs are treated in an implementation dependent way. -% - Require warning if for-in is used on object with no "iterator" member. -% -% 1.9 - ECMA-408 - 3rd Edition -% - -\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 \code{Object} with methods such as \code{noSuchMethod}, \code{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 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 \NoIndex{verbosity} to refer to the property of excess verbiage', -and add a marker in the margin. -% 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}\color{commentaryColor} - ::= - \alt - \alt - \alt * - \alt + - \alt ? - \alt ( ) - \alt \~{} - \alt `aTerminal' - \alt -\end{grammar} - -\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 \Index{term} is a syntactic construct. -It may be considered to be a piece of text which is derivable in the grammar, -and it may be considered to be a tree created by such a derivation. -An \Index{immediate subterm} of a given term $t$ is a syntactic construct -which corresponds to an immediate subtree of $t$ considered as a derivation tree. -A \Index{subterm} of a given term $t$ is $t$, -or an immediate subterm of $t$, -or a subterm of an immediate subterm of $t$. - -\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{}% -For $j \in 1 .. n$, -let $y_j$ be an atomic syntactic entity (like an identifier), -$x_j$ a composite syntactic entity (like an expression or a type), -and $E$ again a composite syntactic entity. -The notation -\IndexCustom{$[x_1/y_1, \ldots, x_n/y_n]E$}{[x1/y1, ..., xn/yn]E@$[x/y\ldots]E$} -then denotes a copy of $E$ -in which each occurrence of $y_i, 1 \le i \le n$ has been replaced by $x_i$. - -\LMHash{}% -This operation is also known as \Index{substitution}, -and it is the variant that avoids capture. -That is, when $E$ contains a construct that introduces $y_i$ into a nested scope for some $i \in 1 .. n$, -the substitution will not replace $y_i$ in that scope. -Conversely, if such a replacement would put an identifier \id{} (a subterm of $x_i$) into a scope where \id{} is declared, -the relevant declarations in $E$ are systematically renamed to fresh names. - -\commentary{ -In short, capture freedom ensures that the ``meaning'' of each identifier is preserved during substitution. -} - -\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 -\code{$x$ \metavar{op} $y$} -is equivalent to the method invocation -\IndexCustom{\rm\code{$x$.\metavar{op}($y$)}}{x.op(y)@\code{$x$.\metavar{op}($y$)}}. -Such specifications should be understood as a shorthand for: -\begin{itemize} -\item - $x$ $op$ $y$ is equivalent to the method invocation - \code{$x$.\metavar{op'}($y$)}, - assuming the class of $x$ actually declared a non-operator method named $op'$ - defining the same function as the operator $op$. -\end{itemize} - -\rationale{ -This circumlocution is required because -{\rm\code{$x$.\metavar{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{}% -When the specification refers to a -\IndexCustom{fresh variable}{variable!fresh}, -it means a variable with a name that doesn't occur anywhere -in the current program. -When the specification introduces a fresh variable bound to an object, -the fresh variable is implicitly bound in a surrounding scope. - -\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, respectively, the root of the class hierarchy and -the reification of run-time types. -% -It would be possible to declare, e.g., -a local variable named \code{Object}, -so it is generally incorrect to assume that -the name \code{Object} will actually resolve to said core class. -However, we will generally omit mentioning this, for brevity.% -} - -%% TODO(eernst): We need to get rid of the concept of `is equivalent to`, -%% cf. language issue https://github.com/dart-lang/language/issues/227. -%% In this CL the phrase `treated as` has been introduced in a few places, -%% and the above-mentioned issue 227 will give rise to a complete revision -%% of this aspect of this document. In particular, the next paragraph will -%% be deleted. - -\LMHash{}% -When the specification says that one piece of syntax \Index{is equivalent to} -another piece of syntax, it means that it is equivalent in all ways, -and the former syntax should generate the same compile-time errors -and have the same run-time behavior as the latter, if any. -\commentary{% -Error messages, if any, should always refer to the original syntax.% -} -If execution or evaluation of a construct is said to be -equivalent to execution or evaluation of another construct, -then only the run-time behavior is equivalent, -and compile-time errors apply only for the original syntax. - -\LMHash{}% -When the specification says that one piece of syntax $s$ is -\Index{treated as} -another piece of syntax $s'$, -it means that the static analysis of $s$ is the static analysis of $s'$ -(\commentary{in particular, exactly the same compile-time errors occur}). -Moreover, if $s$ has no compile-time errors then -the behavior of $s$ at run time is exactly the behavior of $s'$. - -\rationale{% -Error \emph{messages}, if any, should always refer to the original syntax $s$.% -} - -\commentary{% -In short, whenever $s$ is treated as $s'$, -the reader should immediately switch to the section about $s'$ -in order to get any further information about -the static analysis and dynamic semantics of $s$.% -} - -\rationale{% -The notion of being `treated as' is similar to the notion of syntactic sugar: -``$s$ is treated as $s'$'' -could as well have been worded -``$s$ is desugared into $s'$''. -Of course, it should then actually be called ``semantic sugar'', -because the applicability of the transformation and the construction of $s'$ -may rely on information from static analysis. - -The point is that we only specify the static analysis and dynamic semantics -of a core language which is a subset of Dart -(just slightly smaller than Dart), -and desugaring transforms any given Dart program to -a program in that core language. -This helps keeping the language specification consistent and comprehensible, -because it shows directly -that some language features are introducing essential semantics, -and others are better described as mere abbreviations of existing constructs.% -} - - -\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. -Programs with compile-time errors do not have a specified dynamic semantics. -This specification makes no attempt to answer additional questions -about a library or program at the point -where it is known to have a compile-time error. - -\commentary{ -However, tools may choose to support execution of some programs with errors. -For instance, a compiler may compile certain constructs with errors such that -a dynamic error will be raised if an attempt is made to -execute such a construct, -or an IDE integrated runtime may support opening -an editor window when such a construct is executed, -allowing developers to correct the error. -It is expected that such features would amount to a natural extension of the -dynamic semantics of Dart as specified here, but, as mentioned, -this specification makes no attempt to specify exactly what that means. -} - -\LMHash{}% -As specified in this document, -dynamic checks are guaranteed to be performed in certain situations, -and certain violations of the type system throw exceptions at run time. - -\commentary{ -An implementation is free to omit such checks whenever they are -guaranteed to succeed, e.g., based on results from the static analysis. -} - -\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 run time - and may always be queried by dynamic typechecking constructs - (the analogs of instanceOf, casts, typecase etc.\ in other languages). - Reified type information includes - access to instances of class \code{Type} representing types, - the run-time type (aka class) of an object, - and the actual values of type parameters - to constructors and generic function invocations. -\item - Type annotations declare the types of - variables and functions (including methods and constructors). -\item - %% TODO(eernst): Change when integrating instantiate-to-bounds.md. - Type annotations may be omitted, in which case they are generally - filled in with the type \DYNAMIC{} - (\ref{typeDynamic}). -\end{enumerate} -} - -%% TODO(eernst): Update when we add inference. -\commentary{ -Dart as implemented includes extensive support for inference of omitted types. -This specification makes the assumption that inference has taken place, -and hence inferred types are considered to be present in the program already. -However, in some cases no information is available -to infer an omitted type annotation, -and hence this specification still needs to specify how to deal with that. -A future version of this specification will also specify type inference. -} - -\LMHash{}% -Dart programs are organized in a modular fashion into -units called \NoIndex{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. -} - -\LMHash{}% -A dart program execution may occur with assertions enabled or disabled. -The method used to enable or disable assertions is implementation specific. - - -\subsection{Scoping} -\LMLabel{scoping} - -\LMHash{}% -A \Index{namespace} is a mapping of names denoting declarations to actual declarations. -Let $NS$ be a namespace. -We say that a name $n$ \Index{is in} $NS$ if $n$ is a key of $NS$. -We say a declaration $d$ \NoIndex{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 getter with the same name in Dart. -Similarly one cannot declare a top-level function with the same name as a library variable or a 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 \Index{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 \Index{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$ \Index{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 could create unexpected situations as code evolves. -Specifically, the behavior of code in a subclass could silently change 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 \Index{privacy}: public and private. -A declaration is \IndexCustom{private}{private!declaration} -if{}f its name is private, -otherwise it is \IndexCustom{public}{public!declaration}. -A name $q$ is \IndexCustom{private}{private!name} -if{}f any one of the identifiers that comprise $q$ is private, -otherwise it is \IndexCustom{public}{public!name}. -An identifier is \IndexCustom{private}{private!identifier} -if{}f it begins with an underscore (the \_ character) -otherwise it is \IndexCustom{public}{public!identifier}. - -\LMHash{}% -A declaration $m$ is \Index{accessible to a 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 \Index{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{}% -\IndexCustom{Compile-time errors}{compile-time error} -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. - -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. - -A Dart development environment might choose to support error eliminating program transformations, e.g., -replacing an erroneous expression by the invocation of a debugger. -It is outside the scope of this document to specify how such transformations work, and where they may be applied. -} - -\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 \Index{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{}% -\IndexCustom{Static warnings}{static warning} -are situations that do not preclude execution, -but which are unlikely to be intended, -and likely to cause bugs or inconveniences. -A static warning must be reported by a Dart compiler before the associated code is executed. - -\LMHash{}% -When this specification says that a \Index{dynamic error} occurs, -it means that a corresponding error object is thrown. -When it says that a \Index{dynamic type error} occurs, -it represents a failed type check at run time, -and the object which is thrown implements \code{TypeError}. - -\LMHash{}% -Whenever we say that an exception $ex$ is -\IndexCustom{thrown}{throwing an exception}, -it acts like an expression had thrown (\ref{statementCompletion}) -with $ex$ as exception object and with a stack trace -corresponding to the current system state. -When we say that a $C$ \IndexCustom{is thrown}{throwing a class}, -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} - ::= (`,' )* - - ::= \COVARIANT{}? - - ::= \FINAL{} ? - \alt \CONST{} ? - \alt - - ::= \VAR{} - \alt - - ::= \gnewline{} - (`=' )? (`,' )* - - ::= (`=' )? - - ::= (`,' )* -\end{grammar} - -\LMHash{}% -A \synt{variableDeclaration} that declares two or more variables -is equivalent to multiple variable declarations declaring -the same set of variable names in the same order, -with the same type and modifiers. - -\LMHash{}% -An \synt{initializedVariableDeclaration} -that declares two or more variables -is equivalent to multiple variable declarations declaring -the same set of variable names, in the same order, -with the same initialization, type, and modifiers. - -\commentary{ -For example, -\code{\VAR{} x, y;} -is equivalent to -\code{\VAR{} x; \VAR{} y;} -and -\code{\STATIC{} \FINAL{} String s1, s2 = "foo";} -is equivalent to -\code{\STATIC{} \FINAL{} String s1; \STATIC{} \FINAL{} String s2 = "foo";}. -} - -\LMHash{}% -It is possible for a variable declaration to include the modifier \COVARIANT{}. -The effect of doing this with an instance variable is described elsewhere -(\ref{instanceVariables}). -It is a compile-time error for the declaration of -a variable which is not an instance variable -to include the modifier \COVARIANT{}. - -\LMHash{}% -In a variable declaration of one of the forms -\code{$N$ $v$;} -\code{$N$ $v$ = $e$;} -where $N$ is derived from -\syntax{ }, -we say that $v$ is the \Index{declaring occurrence} of the identifier. -For every identifier which is not a declaring occurrence, -we say that it is an \Index{referencing occurrence}. -We also abbreviate that to say that an identifier is -a \Index{declaring identifier} respectively an \Index{referencing identifier}. - -\commentary{ -In an expression of the form \code{$e$.\id} it is possible that -$e$ has static type \DYNAMIC{} and \id{} cannot be associated with -any specific declaration named \id{} at compile-time, -but in this situation \id{} is still a referencing identifier. -} - -\LMHash{}% -An \Index{initializing variable declaration} -is a variable declaration whose declaring identifier is -immediately followed by `\code{=}' and an \Index{initializing expression}. - -\LMHash{}% -A variable declared at the top-level of a library is referred to as either a -\IndexCustom{library variable}{variable!library} or a -\IndexCustom{top-level variable}{variable!top-level}. - -\LMHash{}% -A \IndexCustom{static variable}{variable!static} -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{}% -A \IndexCustom{constant variable}{variable!constant} -is a variable whose declaration includes the modifier \CONST{}. -A constant variable must be initialized to a constant expression (\ref{constants}) or a compile-time error occurs. - -\commentary{% -An initializing expression of a constant variable occurs in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly.% -} - -\LMHash{}% -A \IndexCustom{final variable}{variable!final} -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. -A variable is final if{}f its declaration includes the modifier \FINAL{} or the modifier \CONST{}. - -\LMHash{}% -A \IndexCustom{mutable variable}{variable!mutable} -is a variable which is not final. - -%% Note that the following relies on the assumption that inference has -%% already taken place, including member signature inference. For instance, -%% if `var x;` is an instance variable declaration that overrides `T get x;` -%% then we treat `var x;` as if it had been `T x;`. - -\LMHash{}% -The following rules on implicitly induced getters and setters -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$;} -induces an implicit getter function (\ref{getters}) with signature -\code{$T$ \GET{} $v$} -whose invocation evaluates as described below -(\ref{evaluationOfImplicitVariableGetters}). -In these cases the static type of $v$ is $T$. - -\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$;} -induces an implicit getter function with signature -\code{\DYNAMIC{} \GET{} $v$} -whose invocation evaluates as described below -(\ref{evaluationOfImplicitVariableGetters}). -%% TODO[inference]: We assume inference has taken place, i.e., inferred types -%% are written explicitly. Does this mean that the initialized variants -%% cannot exist (not even for `$e$` of type `dynamic`?). We probably don't -%% want to start talking about a grammar before inference and another one -%% after inference. -In these cases, the static type of $v$ is \DYNAMIC{} -(\ref{typeDynamic}). - -\LMHash{}% -A mutable variable declaration of the form -\code{{} $T$ $v$;} -or \code{$T$ $v$ = $e$;} -induces an implicit setter function (\ref{setters}) with signature -\code{\VOID{} \SET{} $v$=($T$ $x$)} -whose execution sets the value of $v$ to the incoming argument $x$. - -\LMHash{}% -A mutable variable declaration of the form -\code{\VAR{} $v$;} -or \code{\VAR{} $v$ = $e$;} -induces an implicit setter function with signature -\code{\VOID{} \SET{} $v$=(\DYNAMIC{} $x$)} -whose execution sets the value of $v$ to the incoming argument $x$. - -\LMHash{}% -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{}% -Let $v$ be variable declared in an initializing variable declaration, -and let $e$ be the associated initializing expression. -It is a compile-time error if the static type of $e$ is not assignable to the declared type of $v$. -It is a compile-time error if a final instance variable whose declaration has an initializer expression -is also initialized by a constructor, either by an initializing formal or an initializer list entry. - -\commentary{ -It is a compile-time error if a final instance variable -that has been initialized by means of an initializing formal of a constructor $k$ -is also initialized in the initializer list of $k$ (\ref{initializerLists}). - -%% TODO(eernst): Not quite true, because of special lookup for assignment! -A static final variable $v$ does not induce a setter, -so unless a setter named \code{$v$=} is in scope -it is a compile-time error to assign to $v$. - -Similarly, assignment to a final instance variable $v$ -is a compile-time error, -unless a setter named \code{$v$=} is in scope, -or the receiver has type \DYNAMIC{}. -$v$ can be initialized in its declaration or in initializer lists, -but initialization and assignment is not the same thing. -When the receiver has type \DYNAMIC{} -such an assignment is not a compile-time error, -% This error can occur because the receiver is dynamic. -but if there is no setter it will cause a dynamic error. -} - -\LMHash{}% -A variable that has no initializing expression has the null object (\ref{null}) as its initial value. -Otherwise, variable initialization proceeds as follows: - -\LMHash{}% -Static variable declarations with an initializing expression are initialized lazily -(\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. -} - -\commentary{ -Initialization of an instance variable with no initializing expression -takes place during constructor execution -(\ref{initializerLists}). -} - -\LMHash{}% -Initialization of an instance variable $v$ -with an initializing expression $e$ -proceeds as follows: -$e$ is evaluated to an object $o$ -and the variable $v$ is bound to $o$. - -\commentary{ -It is specified elsewhere when this initialization occurs, -and in which environment -(p.\,\pageref{executionOfGenerativeConstructors}, -\ref{localVariableDeclaration}, -\ref{bindingActualsToFormals}). -} - -\commentary{ -If the initializing expression throws then -access to the uninitialized variable is prevented, -because the instance creation -that caused this initialization to take place -will throw. -} - -\LMHash{}% -% This error can occur due to implicit casts, and -% for instance variables also when a setter is called dynamically. -It is a dynamic type error if the dynamic type of $o$ is not -a subtype of the actual type of the variable $v$ -(\ref{actualTypeOfADeclaration}). - - -\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 variable -(\commentary{which can be a 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 initializing expression $e$ is evaluated. -If, during the evaluation of $e$, the getter for $v$ is invoked, -a \code{CyclicInitializationError} is thrown. -If the evaluation of $e$ throws an exception $e$ and stack trace $s$, -the null object (\ref{null}) is stored into $v$; -the execution of the getter then throws $e$ and stack trace $s$. -Otherwise, the evaluation of $e$ succeeded yielding an object $o$; -then $o$ is stored into $v$ and -the execution of the getter completes by returning $o$. -Otherwise, -(\commentary{when a value $o$ has been stored in $v$}) -execution of the getter completes by returning $o$. -\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 constant expression $e$. -\commentary{ -Note that a constant expression cannot depend on itself, -so no cyclic references can occur. -} -\item {\bf Variable declaration without initializer}. -The result of executing the getter method is the value stored in $v$. -\commentary{This may be the initial value, that is, the null object.} -\end{itemize} - - -\section{Functions} -\LMLabel{functions} - -\LMHash{}% -Functions abstract over executable actions. - -\begin{grammar} - ::= \gnewline{} - ? - - ::= ? - - ::= \ASYNC{}? `=>' `;' - \alt (\ASYNC{} | \ASYNC `*' | \SYNC `*')? - - ::= `{' `}' -\end{grammar} - -\LMHash{}% -Functions can be introduced by function declarations (\ref{functionDeclarations}), -method declarations (\ref{instanceMethods}, \ref{staticMethods}), -getter declarations (\ref{getters}), -setter declarations (\ref{setters}), -and constructor declarations (\ref{constructors}); -and they can be introduced by function literals (\ref{functionExpressions}). - -\LMHash{}% -A function is \IndexCustom{asynchronous}{function!asynchronous} -if its body is marked with the \ASYNC{} or \code{\ASYNC*} modifier. -Otherwise the function is \IndexCustom{synchronous}{function!synchronous}. -A function is a \IndexCustom{generator}{function!generator} -if its body is marked with the \code{\SYNC*} or \code{\ASYNC*} modifier. -Further details about these concepts are given below. - -\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 \emph{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{}% -Each declaration that introduces a function has a signature that specifies -its return type, name, and formal parameter part, -except that the return type may be omitted, -and getters never have a formal parameter part. -Function literals have a formal parameter part, but no return type and no name. -The formal parameter part optionally specifies -the formal type parameter list of the function, -and it always specifies its formal parameter list. -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, \code{\ASYNC*} or \code{\SYNC*}. - % - Unless it is statically known that the body of the function - cannot complete normally - (\commentary{that is, it cannot reach the end and ``fall through''}, - cf.~\ref{statementCompletion}), - it is a compile-time error if - the addition of \code{\RETURN;} at the end of the body - would be a compile-time error. - \commentary{% - For instance, it is an error if - the return type of a synchronous function is \code{int}, - and the body may complete normally. - The precise rules are given in section~\ref{return}.% - } - - \commentary{% - Because Dart supports dynamic function invocations, - 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 function body that ends without doing a throw or return - will cause the function to return the null object (\ref{null}), - as will a \RETURN{} without an expression. - For generator functions, the situation is more subtle. - See further discussion in section~\ref{return}.% - } - -OR -\item - of the form \code{=> $e$} or the form \code{\ASYNC{} => $e$}, - which both return the value of the expression $e$ as if by a - \code{return $e$}. - \commentary{% - The other modifiers do not apply here, - because they apply only to generators, discussed below. - Generators are not allowed to return a value, - values are added to the generated stream or iterable using - \YIELD{} or \YIELD*.% - } - Let $T$ be the declared return type of the function that has this body. - It is a compile-time error if one of the following conditions hold: - \begin{itemize} - \item The function is synchronous, $T$ is not \VOID{}, - and it would have been a compile-time error to declare the function with the body - \code{\{ \RETURN{} $e$; \}} - rather than \code{=> $e$}. - \commentary{% - In particular, $e$ can have \emph{any} type when the return type is \VOID.% - } - \rationale{% - This enables concise declarations of \VOID{} functions. - It is reasonably easy to understand such a function, - because the return type is textually near to the returned expression $e$. - In contrast, \code{\RETURN{} $e$;} in a block body is only allowed - for an $e$ with one of a few specific static types, - because it is less likely that the developer understands - that the returned value will not be used - (\ref{return}).% - } - \item The function is asynchronous, \flatten{T} is not \VOID{}, - and it would have been a compile-time error to declare the function with the body - \code{\ASYNC{} \{ \RETURN{} $e$; \}} - rather than \code{\ASYNC{} => $e$}. - \commentary{% - In particular, $e$ can have \emph{any} type - when the flattened return type is \VOID,% - } - \rationale{% - and the rationale is similar to the synchronous case.% - } - \end{itemize} -\end{itemize} - -\LMHash{}% -It is a compile-time error if an \ASYNC, \code{\ASYNC*} or \code{\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. - -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 \code{\ASYNC*} and a factory for \code{Iterable} could be modified by \code{\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 compile-time error if the declared return type of a function marked \ASYNC{} is not a supertype of \code{Future<$T$>} for some type $T$. -It is a compile-time error if the declared return type of a function marked \code{\SYNC*} is not a supertype of \code{Iterable<$T$>} for some type $T$. -It is a compile-time error if the declared return type of a function marked \code{\ASYNC*} is not a supertype of \code{Stream<$T$>} for some type $T$. - - -\subsection{Function Declarations} -\LMLabel{functionDeclarations} - -\LMHash{}% -A \Index{function declaration} is a function that is neither a member of a class nor a function literal. -Function declarations include exactly the following: -\IndexCustom{library functions}{function!library}, -which are function declarations -%(including getters and setters) -at the top level of a library, and -\IndexCustom{local functions}{function!local}, -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}). - -\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$ \Index{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 non-getter function declaration includes a \Index{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 set of named parameters or as a list of positional parameters, but not both. - -\LMHash{}% -Some function declarations include a -\Index{formal type parameter list} (\ref{functions}), -in which case we say that it is a -\IndexCustom{generic function}{function!generic}. -A \IndexCustom{non-generic function}{function!non-generic} -is a function which is not generic. - -\LMHash{}% -The \Index{formal parameter part} of a function declaration consists of the formal type parameter list, if any, and the formal parameter list. - -\commentary{ -The following kinds of functions cannot be generic: -Getters, setters, operators, and constructors. -} - -\LMHash{}% -The formal type parameter list of a function declaration introduces -a new scope known as the function's -\IndexCustom{type parameter scope}{scope!type parameter}. -The type parameter scope of a generic function $f$ is enclosed in the scope where $f$ is declared. -Every formal type parameter introduces a type into the type parameter scope. - -\LMHash{}% -If it exists, the type parameter scope of a function $f$ is the current scope for the signature of $f$, and for the formal type parameter list itself; -otherwise the scope where $f$ is declared is the current scope for the signature of $f$. - -\commentary{ -This means that formal type parameters are in scope in the bounds of parameter declarations, -allowing for so-called F-bounded type parameters like - -\code{class C{}> \{ \ldots{} \}}, - -\noindent -and the formal type parameters are in scope for each other, allowing dependencies like -\code{class D \{ \ldots{} \}}. -} - -\LMHash{}% -The formal parameter list of a function declaration introduces a new scope known as the function's -\IndexCustom{formal parameter scope}{scope!formal parameter}. -The formal parameter scope of a non-generic function $f$ is enclosed in the scope where $f$ is declared. -The formal parameter scope of a generic function $f$ is enclosed in the type parameter scope of $f$. -Every formal parameter introduces a local variable into the formal parameter scope. -The current scope for the function's signature is the scope that encloses the formal parameter scope. - -\commentary{ -This means that in a generic function declaration, -the return type and parameter type annotations can use the formal type parameters, -but the formal parameters are not in scope in the signature. -} - -\LMHash{}% -The body of a function declaration introduces a new scope known as the function's -\IndexCustom{body scope}{scope!function body}. -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} - ::= `(' `)' - \alt `(' `,'? `)' - \alt `(' `,' `)' - \alt `(' `)' - - ::= \gnewline{} - (`,' )* - - ::= - \alt - - ::= \gnewline{} - `[' (`,' )* `,'? `]' - - ::= \gnewline{} - `{' (`,' )* `,'? `}' -\end{grammar} - -Formal parameter lists allow an optional trailing comma after the last parameter (\syntax{`,'?}). -A parameter list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma. -All parameter lists in this specification are shown without a trailing comma, but the rules and semantics apply equally to the corresponding parameter list with a trailing comma. - - -\subsubsection{Required Formals} -\LMLabel{requiredFormals} - -\LMHash{}% -A \Index{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} - ::= - \alt - \alt - - ::= \gnewline{} - \COVARIANT{}? ? - - ::= - \alt \COVARIANT{}? - - ::= \gnewline{} - ? \THIS{} `.' \gnewline{} - ? -\end{grammar} - -\LMHash{}% -It is possible to include the modifier \COVARIANT{} -in some forms of parameter declarations. -The effect of doing this is described in a separate section -(\ref{covariantParameters}). - -\commentary{ -Note that the non-terminal \synt{normalFormalParameter} is also used -in the grammar rules for optional parameters, -which means that such parameters can also be covariant. -} - -\LMHash{}% -It is a compile-time error if the modifier \COVARIANT{} occurs on a parameter of a function which is not an instance method, instance setter, or instance operator. - - -\subsubsection{Optional Formals} -\LMLabel{optionalFormals} - -\LMHash{}% -Optional parameters may be specified and provided with default values. - -\begin{grammar} - ::= (`=' )? - - ::= (`=' )? - \alt ( `:' )? -\end{grammar} - -The form \syntax{ `:' } -is equivalent to the form -\syntax{ `=' }. -The colon-syntax is included only for backwards compatibility. -It is deprecated and will be removed in a later version of the language specification. - -\LMHash{}% -It is a compile-time error if the default value of an optional parameter is not a constant expression (\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. -} - - -\subsubsection{Covariant Parameters} -\LMLabel{covariantParameters} - -\LMHash{}% -Dart allows formal parameters of instance methods, -including setters and operators, -to be declared \COVARIANT{}. -\commentary{ -The syntax for doing this is specified in an earlier section (\ref{requiredFormals}). -} - -\LMHash{}% -It is a compile-time error if the modifier \COVARIANT{} occurs -in the declaration of a formal parameter of a function -which is not an instance method, an instance setter, or an operator. - -\commentary{ -As specified below, a parameter can also be covariant for other reasons. -The overall effect of having a covariant parameter $p$ -in the signature of a given method $m$ -is to allow the type of $p$ to be overridden covariantly, -which means that the type required at run time for a given actual argument -may be a proper subtype of the type which is known at compile time -at the call site. -} - -\rationale{ -This mechanism allows developers to explicitly request that -a compile-time guarantee which is otherwise supported -(namely: that an actual argument whose static type satisfies the requirement -will also do so at run time) -is replaced by dynamic type checks. -In return for accepting these dynamic type checks, -developers can use covariant parameters to express software designs -where the dynamic type checks are known (or at least trusted) to succeed, -based on reasoning that the static type analysis does not capture. -} - -\LMHash{}% -Let $m$ be a method signature with formal type parameters -\List{X}{1}{s}, -positional formal parameters \List{p}{1}{n}, -and named formal parameters \List{q}{1}{k}. -Let $m'$ be a method signature with formal type parameters -\List{X'\!}{1}{s}, -positional formal parameters \List{p'\!}{1}{n'}, -and named formal parameters \List{q'\!}{1}{k'}. -% -Assume that $j \in 1 .. n'$, and $j \leq n$; -we say that $p'_j$ is the parameter in $m'$ that -\IndexCustom{corresponds}{parameter corresponds to parameter} -to the formal parameter $p_j$ in $m$. -Assume that $j \in 1 .. k'$ and $l \in 1 .. k$; -we say that $q'_j$ is the parameter in $m'$ that -\NoIndex{corresponds} to the formal parameter -$q_l$ in $m$ if $q'_j = q_l$. -% -Similarly, we say that the formal type parameter -$X'_j$ from $m'$ -\NoIndex{corresponds} to the formal type parameter -$X_j$ from $m$, for all $j \in 1 .. s$. - -\commentary{ -This includes the case where $m$ respectively $m'$ has -optional positional parameters, -in which case $k = 0$ respectively $k' = 0$ must hold, -but we can have $n \not= n'$. -The case where the numbers of formal type parameters differ is not relevant. -} - -% Being covariant is a property of a parameter of the interface of a class; -% this means that we only talk about the originating keyword \COVARIANT{} -% and the class that contains the relevant declaration when we detect for -% the first time that a given parameter is covariant. From that point and on -% it is "carried" along the subtype links associated with class interfaces, -% such that we can get it inductively from an indirect superinterface just -% by checking whether the direct superinterfaces "have" a method signature -% with the relevant name and a corresponding parameter, and then checking -% that parameter. The same approach is applicable for covariant-by-class. - -\LMHash{}% -Let $C$ be a class that declares a method $m$ which has -a parameter $p$ whose declaration has the modifier \COVARIANT{}; -in this case we say that the parameter $p$ is -\IndexCustom{covariant-by-declaration}{parameter!covariant-by-declaration}. -% -In this case the interface of $C$ has the method signature $m$, -and that signature has the parameter $p$; -we also say that the parameter $p$ in this method signature is -\NoIndex{covariant-by-declaration}. -% -Finally, the parameter $p$ of the method signature $m$ -of the interface of a class $C$ is -\NoIndex{covariant-by-declaration} -if a direct superinterface of $C$ -has an accessible method signature $m'$ with the same name as $m$, -which has a parameter $p'$ that corresponds to $p$, -such that $p'$ is covariant-by-declaration. - -\LMHash{}% -Assume that $C$ is a generic class with formal type parameter declarations -\code{$X_1\ \EXTENDS\ B_1 \ldots,\ X_s\ \EXTENDS\ B_s$}, -let $m$ be a declaration of an instance method in $C$ -(which can be a method, a setter, or an operator), -let $p$ be a parameter declared by $m$, and -let $T$ be the declared type of $p$. -% -The parameter $p$ is -\IndexCustom{covariant-by-class}{parameter!covariant-by-class} -if, for any $j \in 1 .. s$, -$X_j$ occurs in a covariant or an invariant position in $T$. -% -In this case the interface of $C$ also has the method signature $m$, -and that signature has the parameter $p$; -we also say that the parameter $p$ in this method signature is -\NoIndex{covariant-by-class}. -Finally, the parameter $p$ of the method signature $m$ -of the interface of the class $C$ is -\NoIndex{covariant-by-class} -if a direct superinterface of $C$ -has an accessible method signature $m'$ with the same name as $m$, -which has a parameter $p'$ that corresponds to $p$, -such that $p'$ is covariant-by-class. - -\LMHash{}% -A formal parameter $p$ is -\IndexCustom{covariant}{parameter!covariant} -if $p$ is covariant-by-declaration or $p$ is covariant-by-class. - -\commentary{ -It is possible for a parameter to be simultaneously -covariant-by-declaration and covariant-by-class. -Note that a parameter may be -covariant-by-declaration or covariant-by-class -based on a declaration in any direct or indirect superinterface, -including any superclass: -The definitions above propagate these properties -to an interface from each of its direct superinterfaces, -but they will in turn receive the property from their direct superinterfaces, -and so on. -} - - -\subsection{Type of a Function} -\LMLabel{typeOfAFunction} - -\LMHash{}% -This section specifies the static type which is ascribed to -the function denoted by a function declaration, -and the dynamic type of the corresponding function object. - -\LMHash{}% -In this specification, -the notation used to denote the type of a function, -that is, a \Index{function type}, -follows the syntax of the language, -except that \EXTENDS{} is abbreviated to -\FunctionTypeExtends. -This means that every function type is of one of the forms -\FunctionTypePositionalStd{T_0} -\FunctionTypeNamedStd{T_0} - -\noindent -where $T_0$ is the return type, -$X_j$ are the formal type parameters with bounds $B_j$, $j \in 1 .. s$, -$T_j$ are the formal parameter types for $j \in 1 .. n + k$, -and $x_{n+j}$ are the names of named parameters for $j \in 1 .. k$. -Non-generic function types are covered by the case $s = 0$, -where the type parameter declaration list -\code{<\ldots{}>} -as a whole is omitted. -% -Similarly, the optional brackets \code{[]} and \code{\{\}} are omitted -when there are no optional parameters. - -% We promise that the two forms always get the same treatment for k=0. -\commentary{ -Both forms with optionals cover function types with no optionals when $k = 0$, -and every rule in this specification is such that -any of the two forms may be used without ambiguity -to determine the treatment of function types with no optionals. -} - -\LMHash{}% -If a function declaration does not declare a return type explicitly, -its return type is \DYNAMIC{} (\ref{typeDynamic}), -unless it is a constructor, -in which case it is not considered to have a return type, -or it is a setter or operator \code{[]=}, -in which case its return type is \VOID{}. - -\LMHash{}% -A function declaration may declare formal type parameters. -The type of the function includes the names of the type parameters -and for each type parameter the upper bound, -which is considered to be the built-in class \code{Object} if no bound is specified. -When consistent renaming of type parameters can make two function types identical, -they are considered to be the same type. - -\commentary{ -It is convenient to include the formal type parameter names in function types -because they are needed in order to express such things as relations among -different type parameters, F-bounds, and the types of formal parameters. -However, we do not wish to distinguish between two function types if they have -the same structure and only differ in the choice of names. -This treatment of names is also known as alpha-equivalence. -} - -\LMHash{}% -In the following three paragraphs, -if the number $m$ of formal type parameters is zero then -the type parameter list in the function type is omitted. - -\LMHash{}% -Let $F$ be a function with -type parameters \TypeParametersStd, -required formal parameter types \List{T}{1}{n}, -return type $T_0$, -and no optional parameters. -Then the static type of $F$ is -\FunctionTypeAllRequiredStd{T_0}. - -\LMHash{}% -Let $F$ be a function with -type parameters \TypeParametersStd, -required formal parameter types \List{T}{1}{n}, -return type $T_0$ -and positional optional parameter types \List{T}{n+1}{n+k}. -Then the static type of $F$ is -\FunctionTypePositionalStd{T_0}. - -\LMHash{}% -Let $F$ be a function with -type parameters \TypeParametersStd, -required formal parameter types \List{T}{1}{n}, -return type $T_0$, -and named parameters \PairList{T}{x}{n+1}{n+k}, -where $x_{n+j}$, $j \in 1 .. k$ may or may not have a default value. -Then the static type of $F$ is -\FunctionTypeNamedStd{T_0}. - -\LMHash{}% -Let $T$ be the static type of a function declaration $F$. -Let $u$ be the run-time type of a function object $o$ obtained by -function closurization -(\ref{functionClosurization}) -or instance method closurization -(\ref{ordinaryMemberClosurization}) -applied to $F$, -and let $t$ be the actual type corresponding to $T$ -at the occasion where $o$ was created -(\ref{actualTypeOfADeclaration}). -\commentary{$T$ may contain free type variables, but $t$ contains their actual values.} -The following must then hold: -$u$ is a class that implements the built-in class \FUNCTION{}; -$u$ is a subtype of $t$; -and $u$ is not a subtype of any function type which is a proper subtype of $t$. -\commentary{% -If we had omitted the last requirement then -\code{f \IS{} int\,\FUNCTION([int])} -could evaluate to \TRUE{} with the declaration -\code{\VOID{} f()\,\{\}}, -which is obviously not the intention.% -} - -\rationale{ -It is up to the implementation to choose -an appropriate representation for function objects. -For example, consider that -a function object produced via property extraction -treats equality differently from other function objects, -and is therefore likely a different class. -Implementations may also use different classes for function objects -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, e.g., -one cannot assume that any two distinct function objects -will necessarily have the same run-time type. -} - - -\subsection{External Functions} -\LMLabel{externalFunctions} - -\LMHash{}% -An \IndexCustom{external function}{function!external} -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 run-time system), 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 \emph{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 throw 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 \Index{class} defines the form and behavior of a set of objects which are its -\IndexCustom{instances}{instance}. -Classes may be defined by class declarations as described below, or via mixin applications (\ref{mixinApplication}). - -\begin{grammar} - ::= \ABSTRACT{}? \CLASS{} ? - \gnewline{} ? ? - \gnewline{} `{' ( )* `}' - \alt \ABSTRACT{}? \CLASS{} - - ::= (`,' )* - - ::= `;' - \alt - - ::= ? - \alt - \alt \STATIC{}? - \alt \STATIC{}? - \alt \STATIC{}? - \alt - - ::= ( | )? - \alt ( | )? - \alt \EXTERNAL{} - \alt \EXTERNAL{} - \alt (\EXTERNAL{} \STATIC{}?)? - \alt (\EXTERNAL{} \STATIC{}?)? - \alt \EXTERNAL{}? - \alt (\EXTERNAL{} \STATIC{}?)? - \alt \STATIC{} (\FINAL{} | \CONST{}) ? - \alt \FINAL{} ? - \alt (\STATIC{} | \COVARIANT{})? (\VAR{} | ) - - ::= \gnewline{} - (`,' )* - - ::= `=' -\end{grammar} - -\LMHash{}% -It is possible to include the modifier \COVARIANT{} in some forms of declarations. -The effect of doing this is described elsewhere -(\ref{covariantParameters}). - -\LMHash{}% -A class has constructors, instance members and static members. -The \IndexCustom{instance members}{members!instance} of a class -are its instance methods, getters, setters and instance variables. -The \IndexCustom{static members}{members!static} of a class -are its static methods, getters, setters and class variables. -The \IndexCustom{members}{members} of a class -are its static and instance members. - -\LMHash{}% -A class has several scopes: -\begin{itemize} -\item A \IndexCustom{type-parameter scope}{scope!type parameter}, - 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 \IndexCustom{static scope}{scope!static}. -The enclosing scope of the static scope of a class is the type parameter scope (\ref{generics}) of the class. -\item An \IndexCustom{instance scope}{scope!instance}. -The enclosing scope of a class' instance scope is the class' static scope. -\end{itemize} - -\LMHash{}% -The enclosing scope of an instance member declaration is the instance scope of the class in which it is declared. - -\LMHash{}% -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 by declaring them in its implements clause (\ref{superinterfaces}). - -\LMHash{}% -An \IndexCustom{abstract class declaration}{class declaration!abstract} -is a class declaration that is explicitly declared -with the \ABSTRACT{} modifier. -A \IndexCustom{concrete class declaration}{class declaration!concrete} -is a class declaration that is not abstract. -An \IndexCustom{abstract class}{class!abstract} is a class -whose declaration is abstract, and -a \IndexCustom{concrete class}{class!concrete} is a class -whose declaration is concrete. - -\rationale{ -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. -} - -\commentary{ -The interface of a class $C$ is -an implicit interface that declares instance member signatures -that correspond to the instance members declared by $C$, -and whose direct superinterfaces are -the direct superinterfaces of $C$ -(\ref{interfaces}, \ref{superinterfaces}). -} - -\LMHash{}% -When a class name appears as a type, -that name denotes the interface of the class. - -\LMHash{}% -% The use of 'concrete member' below may seem redundant, because a class -% does not inherit abstract members from its superclass, but this -% underscores the fact that even when an abstract declaration of $m$ is -% declared in $C$, $C$ does not "have" $m$. -A concrete class must fully implement its interface: -Let $C$ be a concrete class with interface $I$. -Assume that $I$ has an accessible member signature $m$. -It is a compile-time error if $C$ does not have -a concrete accessible member with the same name as $m$, -unless $C$ has a non-trivial \code{noSuchMethod} -(\ref{theMethodNoSuchMethod}). -It is a compile-time error if $C$ has -a concrete accessible member with the same name as $m$, -with a method signature $m'$ which is not a correct override of $m$ -(\ref{correctMemberOverrides}), -unless that concrete member is a \code{noSuchMethod} forwarder -(\ref{theMethodNoSuchMethod}). - -\commentary{ -In particular, it is an error for a class to be concrete even if it inherits -a member implementation for every member signature in its interface, -unless each of them has parameters and types such that they satisfy -the corresponding member signature. -But when there is a non-trivial \code{noSuchMethod} it is allowed -to leave some members unimplemented, -and it is allowed to to have a \code{noSuchMethod} forwarder which does not -satisfy the class interface -(in which case it will be overridden by another \code{noSuchMethod} forwarder). -} - -\commentary{ -It is a compile-time error if a class declares two members of the same name, -either because it declares the same name twice in the same scope -(\ref{scoping}), -or because it declares a static member and an instance member -with the same name -(\ref{classMemberConflicts}). -} - -\commentary{ -Here are simple examples, that illustrate the difference between ``has a member'' and ``declares a member''. -For example, \code{B} \IndexCustom{declares}{declares member} - one member named \code{f}, -but \IndexCustom{has}{has member} 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; // \comment{getter i and setter i= override versions from A} - \STATIC{} j; // \comment{compile-time error: static getter \& setter conflict with} - // \comment{instance getter \& setter} -\\ - // \comment{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 named $C$ declares -a member with basename (\ref{classMemberConflicts}) $C$. -If a generic class named $G$ declares a type variable named $X$, -it is a compile-time error -if $X$ is equal to $G$, -if $G$ has a member whose basename is $X$, -and if $G$ has a constructor named \code{$G$.$X$}. - - -\subsection{Instance Methods} -\LMLabel{instanceMethods} - -\LMHash{}% -\IndexCustom{Instance methods}{method!instance} -are functions (\ref{functions}) -whose declarations are immediately contained within a class declaration -and that are not declared \STATIC{}. -The \Index{instance methods of a class} $C$ are the instance methods declared by $C$ -and the instance methods inherited by $C$ from its superclass -(\ref{inheritanceAndOverriding}). - -\LMHash{}% -Consider a class $C$. -It is a compile-time error if an instance method declaration in $C$ has -a member signature $m$ -(\ref{interfaces}) -% Note that $m'$ is accessible, due to the definition of 'overrides'. -which overrides a member signature $m'$ -from a direct superinterface of $C$ -(\ref{interfaceInheritanceAndOverriding}), -unless this is a correct member override -(\ref{correctMemberOverrides}). - -\commentary{ -This is not the only kind of conflict that may exist: -An instance member declaration $D$ may conflict with another declaration $D'$, -even in the case where they do not have the same name -or they are not the same kind of declaration. -E.g., $D$ could be an instance getter and $D'$ a static setter -(\ref{classMemberConflicts}). -} - -\LMHash{}% -For each parameter $p$ of $m$ where \COVARIANT{} is present, -it is a compile-time error if there exists -a direct or indirect superinterface $J$ of $C$ which has -an accessible method signature $m''$ with the same name as $m$, -such that $m''$ has a parameter $p''$ that corresponds to $p$ -(\ref{covariantParameters}), -unless the type of $p$ is assignable to the type of $p''$. - -\commentary{ -This means that -a parameter which is covariant-by-declaration can have a type -which is a supertype or a subtype of the type of -a corresponding parameter in a superinterface, -but the two types cannot be unrelated. -Note that this requirement must be satisfied -for each direct or indirect superinterface separately, -because assignability is not transitive. -} - -\rationale{ -The superinterface may be the statically known type of the receiver, -so this means that we relax the potential typing relationship -between the statically known type of a parameter and the -type which is actually required at run time -to the assignability relationship, -rather than the strict supertype relationship -which applies to a parameter which is not covariant. -It should be noted that it is not statically known -at the call site whether any given parameter is covariant, -because the covariance could be introduced in -a proper subtype of the statically known type of the receiver. -We chose to give priority to flexibility rather than safety here, -because the whole point covariant parameters is that developers -can make the choice to increase the flexibility -in a trade-off where some static type safety is lost. -} - - -\subsubsection{Operators} -\LMLabel{operators} - -\LMHash{}% -\IndexCustom{Operators}{operators} are instance methods with special names. - -\begin{grammar} - ::= \gnewline{} - ? \OPERATOR{} - - ::= `~' - \alt - \alt `[]' - \alt `[]=' - - ::= - \alt - \alt - \alt - \alt `==' - \alt -\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: -\lit{<}, -\lit{>}, -\lit{<=}, -\lit{>=}, -\lit{==}, -\lit{-}, -\lit{+}, -\lit{/}, -\lit{\~{}/}, -\lit{*}, -\lit{\%}, -\lit{|}, -\lit{\^}, -\lit{\&}, -\lit{\ltlt}, -\lit{\gtgt}, -\lit{\gtgtgt}, -\lit{[]=}, -\lit{[]}, -\lit{\~{}}. - -\LMHash{}% -It is a compile-time error if the arity of the user-declared operator -\lit{[]=} is not 2. -It is a compile-time error if the arity of a user-declared operator with one of the names: -\lit{<}, -\lit{>}, -\lit{<=}, -\lit{>=}, -\lit{==}, -\lit{-}, -\lit{+}, -\lit{\~{}/}, -\lit{/}, -\lit{*}, -\lit{\%}, -\lit{|}, -\lit{\^}, -\lit{\&}, -\lit{\ltlt}, -\lit{\gtgt}, -\lit{\gtgtgt}, -\lit{[]} -is not 1. -It is a compile-time error if the arity of the user-declared operator -\lit{-} -is not 0 or 1. - -\commentary{ -The \lit{-} 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 \lit{-} 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 -\lit{\~{}} -is not 0. - -\LMHash{}% -It is a compile-time error to declare an optional parameter in an operator. - -\LMHash{}% -It is a static warning if the return type of a user-declared operator -\lit{[]=} -is explicitly declared and not \VOID{}. - -\commentary{ -If no return type is specified for a user-declared operator -\lit{[]=}, -its return type is \VOID{} (\ref{typeOfAFunction}). -} - -\rationale{ -The return type is \VOID{} because -a return statement in an implementation of operator -\lit{[]=} -does not return a value. -Consider a non-throwing evaluation of an expression $e$ of the form -\code{$e_1$[$e_2$] = $e_3$}, -and assume that the evaluation of $e_3$ yields an instance $o$. -$e$ will then evaluate to $o$, -and even if the executed body of operator -\lit{[]=} -completes with a value $o'$, -that is, if $o'$ is returned, that value is simply ignored. -The rationale for this behavior is that assignments should be guaranteed to evaluate to the assigned value. -} - - -\subsubsection{The Method \code{noSuchMethod}} -\LMLabel{theMethodNoSuchMethod} - -\LMHash{}% -The method \code{noSuchMethod} is invoked implicitly during execution -in situations where one or more member lookups fail -(\ref{ordinaryInvocation}, -\ref{getterAccessAndMethodExtraction}, -\ref{assignment}). - -\commentary{ -We may think of \code{noSuchMethod} as a backup -which kicks in when an invocation of a member $m$ is attempted, -but there is no member named $m$, -or it exists, -but the given invocation has an argument list shape -that does not fit the declaration of $m$ -(passing fewer positional arguments than required or more than supported, -or passing named arguments with names not declared by $m$). -% The next sentence covers both function objects and instances of -% a class with a method named \code{call}, because we would have a -% compile-time error invoking \code{call} with a wrongly shaped argument -% list unless the type is \DYNAMIC{} or \FUNCTION. -This can only occur for an ordinary method invocation -when the receiver has static type \DYNAMIC, -or for a function invocation when -the invoked function has static type \FUNCTION{} or \DYNAMIC. -% -The method \code{noSuchMethod} can also be invoked in other ways, e.g., -it can be called explicitly like any other method, -and it can be invoked from a \code{noSuchMethod} forwarder, -as explained below. -} - -\LMHash{}% -We say that a class $C$ \Index{has a non-trivial \code{noSuchMethod}} -if $C$ has a concrete member named \code{noSuchMethod} -which is distinct from the one declared in the built-in class \code{Object}. - -\commentary{ -Note that it must be a method that accepts one positional argument, -in order to correctly override \code{noSuchMethod} in \code{Object}. -For instance, it can have signature -\code{noSuchMethod(Invocation i)} or -\code{noSuchMethod(Object i, [String s])}, -but not -\code{noSuchMethod(Invocation i, String s)}. -This implies that the situation where \code{noSuchMethod} is invoked -(explicitly or implicitly) -with one actual argument cannot fail for the reason that -``there is no such method'', -such that we would enter an infinite loop trying to invoke \code{noSuchMethod}. -It \emph{is} possible, however, to encounter a dynamic error -during an invocation of \code{noSuchMethod} -because the actual argument fails to satisfy a type check, -but that situation will give rise to a dynamic type error -rather than a repeated attempt to invoke \code{noSuchMethod} -(\ref{bindingActualsToFormals}). -Here is an example where a dynamic type error occurs because -an attempt is made to pass an \code{Invocation} -where only the null object is accepted: -} - -\begin{dartCode} -\CLASS{} A \{ - noSuchMethod(\COVARIANT{} Null n) => n; -\} -\\ -\VOID{} main() \{ - \DYNAMIC{} d = A(); - d.foo(42); // Dynamic type error when invoking noSuchMethod. -\} -\end{dartCode} - -\LMHash{}% -Let $C$ be a concrete class and -let $L$ be the library that contains the declaration of $C$. -The member $m$ is \Index{noSuchMethod forwarded} in $C$ if{}f -one of the following is true: - -\begin{itemize} -\item $C$ has a non-trivial \code{noSuchMethod}, - the interface of $C$ contains $m$, - and $C$ has no concrete declaration of $m$ - (\commentary{that is, no member $m$ is declared or inherited by $C$}). -\item - % Inaccessible private methods are not present in the interface of a class, - % so we need to find a class that can access $m$. - There exists a direct or indirect superinterface - $D$ of $C$ which is declared in the library $L_2$, - the interface of $D$ contains $m$ - (\commentary{which implies that $m$ is accessible to $L_2$}), - $m$ is inaccessible to $L$, - and no superclass of $C$ has - a concrete declaration of $m$ accessible to $L_2$. -\end{itemize} - -\LMHash{}% -For a concrete class $C$, a -\IndexCustom{\code{noSuchMethod} forwarder}{noSuchMethod forwarder} -is implicitly induced for each member $m$ -which is noSuchMethod forwarded. -This is a concrete member of $C$ -with the signature taken from the interface of $C$ respectively $D$ above, -and with the same default value for each optional parameter. -It can be invoked in an ordinary invocation and in a superinvocation, -and when $m$ is a method it can be closurized -(\ref{ordinaryMemberClosurization}) -using a property extraction -(\ref{propertyExtraction}). - -\commentary{ -This implies that a \code{noSuchMethod} forwarder has the same -properties as an explicitly declared concrete member, -except of course that a \code{noSuchMethod} forwarder -does not prevent itself from being induced. -We do not specify the body of a \code{noSuchMethod} forwarder, -but it will invoke \code{noSuchMethod}, -and we specify the dynamic semantics of executing it below. -} - -\commentary{ -At the beginning of this section we mentioned that implicit invocations -of \code{noSuchMethod} can only occur -with a receiver of static type \DYNAMIC{} -or a function of static type \DYNAMIC{} or \FUNCTION{}. -With a \code{noSuchMethod} forwarder, -\code{noSuchMethod} can also be invoked -on a receiver whose static type is not \DYNAMIC{}. -No similar situation exists for functions, -because it is impossible to induce a \code{noSuchMethod} forwarder -into the class of a function object. -} - -\commentary{ -For a concrete class $C$, -we may think of a non-trivial \code{noSuchMethod} -(declared in or inherited by $C$) -as a request for ``automatic implementation'' of all unimplemented members -in the interface of $C$ as \code{noSuchMethod} forwarders. -Similarly, there is an implicit request for -automatic implementation of all unimplemented -inaccessible members of any concrete class, -whether or not there is a non-trivial \code{noSuchMethod}. -Note that the latter cannot be written explicitly in Dart, -because their names are inaccessible; -but the language can still specify that they are induced implicitly, -because compilers control the treatment of private names. -} - -\LMHash{}% -It is a compile-time error if a concrete class $C$ has -a \code{noSuchMethod} forwarded method signature $S$ -for a method named $m$, -and a superclass of $C$ has an accessible concrete declaration of $m$ -which is not a \code{noSuchMethod} forwarder. - -\commentary{ -This can only happen if that concrete declaration does not -correctly override $S$. Consider the following example: -} - -\begin{dartCode} -\CLASS{} A \{ - foo(int i) => \NULL; -\} - -\ABSTRACT{} \CLASS{} B \{ - foo([int i]); -\} - -\CLASS{} C \EXTENDS{} A \IMPLEMENTS{} B \{ - noSuchMethod(Invocation i) => ...; - // Error: Forwarder would override `A.foo`. -\} -\end{dartCode} - -\commentary{ -In this example, -an implementation with signature \code{foo(int i)} is inherited by \code{C}, -and the superinterface \code{B} declares -the signature \code{foo([int i])}. -This is a compile-time error because \code{C} does not have -a method implementation with signature \code{foo([int])}. -We do not wish to implicitly induce -a \code{noSuchMethod} forwarder with signature \code{foo([int])} -because it would override \code{A.foo}, -and that is likely to be highly confusing for developers. -% -In particular, it would cause an invocation like \code{C().foo(42)} -to invoke \code{noSuchMethod}, -even though that is an invocation which is correct for -the declaration of \code{foo} in \code{A}. -% -Hence, we require developers to explicitly resolve the conflict -whenever an implicitly induced \code{noSuchMethod} forwarder -would override an explicitly declared inherited implementation. -% -It is no problem, however, -to let a \code{noSuchMethod} forwarder override -another \code{noSuchMethod} forwarder, -and hence there is no error in that situation. -} - -\LMHash{}% -For the dynamic semantics, -assume that a class $C$ has an implicitly induced -\code{noSuchMethod} forwarder named $m$, -with formal type parameters -\code{$X_1,\ \ldots,\ X_r$}, -positional formal parameters -\code{$a1,\ \ldots,\ a_k$} -(\commentary{some of which may be optional when $m = 0$}), -and named formal parameters with names -\code{$x_1,\ \ldots,\ x_m$} -(\commentary{with default values as mentioned above}). - -\commentary{ -For this purpose we need not distinguish between -a signature that has optional positional parameters and -a signature that has named parameters, -because the former is covered by $m = 0$. -} - -\LMHash{}% -The execution of the body of $m$ creates -an instance $im$ of the predefined class \code{Invocation} -such that: - -\begin{itemize} -\item \code{$im$.isMethod} evaluates to \code{\TRUE{}} if{}f $m$ is a method. -\item \code{$im$.isGetter} evaluates to \code{\TRUE{}} if{}f $m$ is a getter. -\item \code{$im$.isSetter} evaluates to \code{\TRUE{}} if{}f $m$ is a setter. -\item \code{$im$.memberName} evaluates to the symbol \code{m}. -\item \code{$im$.positionalArguments} evaluates to an unmodifiable list - with the same values as the list resulting from evaluation of - \code{[$a_1, \ldots,\ a_k$]}. -\item \code{$im$.namedArguments} evaluates to an unmodifiable map - with the same keys and values as the map resulting from evaluation of - - \code{\{$\#x_1$: $x_1, \ldots,\ \#x_m$: $x_m$\}}. -\item \code{$im$.typeArguments} evaluates to an unmodifiable list - with the same values as the list resulting from evaluation of - \code{[$X_1, \ldots,\ X_r$]}. -\end{itemize} - -\LMHash{}% -Next, \code{noSuchMethod} is invoked with $i$ as the actual argument, -and the result obtained from there is returned by the execution of $m$. - -\commentary{ -This is an ordinary method invocation of \code{noSuchMethod} -(\ref{ordinaryInvocation}). -That is, a \code{noSuchMethod} forwarder in a class $C$ can invoke -an implementation of \code{noSuchMethod} that is declared in -a subclass of $C$. - -Dynamic type checks on the actual arguments passed to $m$ -are performed in the same way as for an invocation of an -explicitly declared method. -In particular, an actual argument passed to a covariant parameter -will be checked dynamically. - -Also, like other ordinary method invocations, -it is a dynamic type error if the result returned by -a \code{noSuchMethod} forwarder has a type which is not a subtype -of the return type of the forwarder. - -One special case to be aware of is where a forwarder is torn off -and then invoked with an actual argument list which does not match -the formal parameter list. -In that situation we will get an invocation of -\code{Object.noSuchMethod} -rather than the \code{noSuchMethod} in the original receiver, -because this is an invocation of a function object -(and they do not override \code{noSuchMethod}): -} - -\begin{dartCode} -\CLASS{} A \{ - noSuchMethod(Invocation i) => \NULL; - \VOID{} foo(); -\} -\\ -\VOID{} main() \{ - A a = A(); - \FUNCTION{} f = a.foo; - // Invokes `Object.noSuchMethod`, which throws. - f(42); -\} -\end{dartCode} - - -\subsubsection{The Operator `=='} -\LMLabel{theOperatorEqualsEquals} - -\LMHash{}% -The operator \lit{==} is used implicitly in certain situations, -and in particular constant expressions -(\ref{constants}) -give rise to constraints on that operator. -In order to specify these constraints just once we introduce the notion of a -% Neither \syntax nor \lit works, so we fall back to `\code{==}'. -\IndexCustom{primitive operator `\code{==}'}{% - operator `\code{==}'!primitive}: - -\begin{itemize} -\item Every instance of type \code{int} and \code{String} - has a primitive operator \lit{==}. -\item Every instance of type \code{Symbol} - which was originally obtained by evaluation of a literal symbol or - a constant invocation of a constructor of the \code{Symbol} class - has a primitive operator \lit{==}. -\item Every instance of type \code{Type} - which was originally obtained by evaluating a constant type literal - (\ref{dynamicTypeSystem}) - has a primitive operator \lit{==}. -\item An instance $o$ has a primitive operator \lit{==} - if the dynamic type of $o$ is a class $C$, - and $C$ has a primitive operator \lit{==}. -\item The class \code{Object} has a primitive operator \lit{==}. -\item A class $C$ has a primitive operator \lit{==} - if it does not have an implementation of the operator \lit{==} - that overrides the one inherited from \code{Object}. - \commentary{% - In particular, the following have a primitive operator \lit{==}: - The null object (\ref{null}), - function objects obtained by function closurization of - a static method or a top-level function - (\ref{functionClosurization}), - instances of type \code{bool} - (\ref{booleans}), - and instances obtained by evaluation of a list literal - (\ref{lists}), - a map literal - (\ref{maps}), or - a set literal - (\ref{sets}). - } -\end{itemize} - -\LMHash{}% -When we say that the operator \lit{==} of a given instance or class -\IndexCustom{is not primitive}{operator `\code{==}'!is not primitive}, -it means that it is not true that said instance or class -has a primitive operator \lit{==}. - - -\subsection{Getters} -\LMLabel{getters} - -\LMHash{}% -Getters are functions (\ref{functions}) that are used to retrieve the values of object properties. - -\begin{grammar} - ::= ? \GET{} -\end{grammar} - -\LMHash{}% -If no return type is specified, the return type of the getter is \DYNAMIC{}. - -\LMHash{}% -A getter definition that is prefixed with the \STATIC{} modifier defines a static getter. -Otherwise, it defines an instance getter. -The name of the getter is given by the identifier in the definition. - -\LMHash{}% -The \Index{instance getters of a class} $C$ are -those instance getters declared by $C$, -either implicitly or explicitly, -and the instance getters inherited by $C$ from its superclass. -The \Index{static getters of a class} $C$ are -those static getters declared by $C$. - -\commentary{ -A getter declaration may conflict with other declarations -(\ref{classMemberConflicts}). -In particular, a getter can never override a method, -and a method can never override a getter or an instance variable. -The rules for when a getter correctly overrides another member -are given elsewhere -(\ref{correctMemberOverrides}). -} - - -\subsection{Setters} -\LMLabel{setters} - -\LMHash{}% -Setters are functions (\ref{functions}) that are used to set the values of object properties. - -\begin{grammar} - ::= ? \SET{} -\end{grammar} - -\commentary{ -If no return type is specified, the return type of the setter is \VOID{} (\ref{typeOfAFunction}). -} - -\LMHash{}% -A setter definition that is prefixed with the \STATIC{} modifier defines a static setter. -Otherwise, it defines an instance setter. -The name of a setter is obtained by appending the string `=' to the identifier given in its signature. - -\commentary{ -Hence, a setter name can never conflict with, override or be overridden by a getter or method. -} - -\LMHash{}% -The \Index{instance setters of a class} $C$ are -those instance setters declared by $C$ -either implicitly or explicitly, -and the instance setters inherited by $C$ from its superclass. -The \Index{static setters of a class} $C$ are -those static setters declared by $C$, -either implicitly or explicitly. - -\LMHash{}% -It is a compile-time error if a setter's formal parameter list -does not consist of exactly one required formal parameter $p$. -\rationale{ -We could enforce this via the grammar, but we'd have to specify the evaluation rules in that case. -} - -\LMHash{}% -It is a static warning if a setter declares a return type other than \VOID{}. -It is a static warning if a class has -a setter named \code{$v$=} with argument type $T$ and -a getter named $v$ with return type $S$, -and $S$ may not be assigned to $T$. - -\commentary{ -The rules for when a setter correctly overrides another member -are given elsewhere -(\ref{correctMemberOverrides}). -A setter declaration may conflict with other declarations as well -(\ref{classMemberConflicts}). -} - - -\subsection{Abstract Instance Members} -\LMLabel{abstractInstanceMembers} - -\LMHash{}% -An \IndexCustom{abstract method}{method!abstract} -(respectively, -\IndexCustom{abstract getter}{getter!abstract} or -\IndexCustom{abstract setter}{setter!abstract}) -is an instance method, getter or setter that is not declared \EXTERNAL{} and does not provide an implementation. -A \IndexCustom{concrete method}{method!concrete} -(respectively, -\IndexCustom{concrete getter}{getter!concrete} or -\IndexCustom{concrete setter}{setter!concrete}) -is an instance method, getter or setter that is not abstract. - -\rationale{ -Abstract instance members are useful because of their interplay with classes. -Every Dart class induces an implicit interface, -and Dart does not support specifying interfaces explicitly. -Using an abstract class instead of a traditional interface -has important advantages. -An abstract class can provide default implementations. -It can also provide static methods, -obviating the need for service classes such as \code{Collections} or \code{Lists}, -whose entire purpose is to group utilities related to a given type. -} - -\commentary{ -Invocation of an abstract method, getter, or setter cannot occur, -because lookup (\ref{lookup}) will never yield an abstract member as its result. -One way to think about this is that -an abstract member declaration in a subclass -does not override or shadow an inherited member implementation. -It only serves to specify the signature of the given member that -every concrete subtype must have an implementation of; -that is, it contributes to the interface of the class, -not to the class itself. -} - -\rationale{ -The purpose of an abstract method is to provide a declaration -for purposes such as type checking and reflection. -In mixins, it is often useful to introduce such declarations for methods that -the mixin expects will be provided by the superclass the mixin is applied to. -} - -\rationale{ -We wish to detect if one declares a concrete class with abstract members. -However, code like the following should work: -} - -\begin{dartCode} -class Base \{ - int get one => 1; -\} -\\ -\ABSTRACT{} \CLASS{} Mix \{ - int get one; - int get two => one + one; -\} -\\ -\CLASS{} C extends Base with Mix \{ \} -\end{dartCode} - -\rationale{ -At run time, the concrete method \code{one} declared in \code{Base} will be executed, and no problem should arise. -Therefore no error should be raised if a corresponding concrete member exists in the hierarchy. -} - - -\subsection{Instance Variables} -\LMLabel{instanceVariables} - -\LMHash{}% -\IndexCustom{Instance variables}{variables!instance} -are variables whose declarations -are immediately contained within a class declaration -and that are not declared \STATIC{}. -The \Index{instance variables of a class} $C$ are -the instance variables declared by $C$ -and the instance variables inherited by $C$ from its superclass. - -\LMHash{}% -It is a compile-time error if an instance variable is declared to be constant. - -\rationale{ -The notion of a constant instance variable is subtle and confusing to programmers. -An instance variable is intended to vary per instance. -A constant instance variable would have the same value for all instances, and as such is already a dubious idea. - -The language could interpret const instance variable declarations as instance getters that return a constant. -However, a constant instance variable could not be treated as a true compile-time constant, as its getter would be subject to overriding. - -Given that the value does not depend on the instance, it is better to use a static class variable. -An instance getter for it can always be defined manually if desired. -} - -\LMHash{}% -It is possible for the declaration of an instance variable -to include the modifier \COVARIANT{} -(\ref{variables}). -The effect of this is that the formal parameter of -the corresponding implicitly induced setter -is considered to be covariant-by-declaration -(\ref{covariantParameters}). - -\commentary{ -The modifier \COVARIANT{} on an instance variable has no other effects. -In particular, the return type of the implicitly induced getter -can already be overridden covariantly without \COVARIANT{}, -and it can never be overridden to a supertype or an unrelated type, -regardless of whether the modifier \COVARIANT{} is present. -} - - -\subsection{Constructors} -\LMLabel{constructors} - -\LMHash{}% -A \Index{constructor} is a special function that is used in instance creation expressions (\ref{instanceCreation}) to obtain objects, typically by creating or initializing them. -Constructors may be generative (\ref{generativeConstructors}) or they may be factories (\ref{factories}). - -\LMHash{}% -A \Index{constructor name} always begins with the name of its immediately enclosing class, and may optionally be followed by a dot and an identifier \id. -It is a compile-time error if the name of a constructor is not a constructor name. - -\LMHash{}% -The -\IndexCustom{function type of a constructor}{function type!of a constructor} -$k$ is the function type -whose return type is the class that contains the declaration of $k$, -and whose formal parameter types, optionality, and names of named parameters -correspond to the declaration of $k$. - -\commentary{ -Note that the function type $F$ of a constructor $k$ may contain -type variables declared by the enclosing class $C$. -In that case we can apply a substitution to $F$, as in -$[T_1/X_1, \ldots, T_m/X_m]F$, -where $X_j, j \in 1 .. m$ are the formal type parameters of $C$ -and $T_j, j \in 1 .. m$ are specified in the given context. -We may also omit such a substitution when the given context is -the instance scope of $C$, where $X_1, \ldots, X_m$ are in scope. -} - -\commentary{ -A constructor declaration may conflict with static member declarations -(\ref{classMemberConflicts}). -} - -% In what scope do constructors go? The simple names of named constructors go in the static scope of the class. Unnamed ones go nowhere, but we use the class name to refer to them; the class name could also in the static scope of the class as well to prevent weird errors, or we could ban it explicitly and avoiding duplication. Similarly, the instance scope could contain the constructor names and class name, or we could have special rules to prevent collisions between instance members and constructors or the class. - -% The enclosing scope of a generative constructor is the instance scope of the class in which it is declared (but what about redirecting?) - -\LMHash{}% -If{}f no constructor is specified for a class $C$, it implicitly has a default constructor \code{C() : \SUPER{}() \{\}}, unless $C$ is class \code{Object}. - - -\subsubsection{Generative Constructors} -\LMLabel{generativeConstructors} - -\LMHash{}% -A \IndexCustom{generative constructor}{constructor!generative} -declaration consists of a constructor name, a constructor parameter list, -and either a redirect clause or an initializer list and an optional body. - -\begin{grammar} - ::= \gnewline{} - (`.' )? -\end{grammar} - -\LMHash{}% -A \Index{constructor parameter list} is a parenthesized, comma-separated list of formal constructor parameters. -A \Index{formal constructor parameter} is either a formal parameter (\ref{formalParameters}) or an initializing formal. -An \Index{initializing formal} has the form \code{\THIS{}.\id}, where \id{} is the name of an instance variable of the immediately enclosing class. -It is a compile-time error if \id{} is not an instance variable of the immediately enclosing class. -It is a compile-time error if an initializing formal is used by a function other than a non-redirecting generative constructor. - -\LMHash{}% -If an explicit type is attached to the initializing formal, that is its static type. -Otherwise, the type of an initializing formal named \id{} is $T_{id}$, where $T_{id}$ is the type of the instance variable named \id{} in the immediately enclosing class. -It is a compile-time error if the static type of \id{} is not a subtype of $T_{id}$. - -\LMHash{}% -Initializing formals constitute an exception to the rule that -every formal parameter introduces a local variable into -the formal parameter scope (\ref{formalParameters}). -When the formal parameter list of a non-redirecting generative constructor -contains any initializing formals, a new scope is introduced, the -\IndexCustom{formal parameter initializer scope}{scope!formal parameter initializer}, -which is the current scope of the initializer list of the constructor, -and which is enclosed in the scope where the constructor is declared. -Each initializing formal in the formal parameter list introduces a final local variable into the formal parameter initializer scope, but not into the formal parameter scope; every other formal parameter introduces a local variable into both the formal parameter scope and the formal parameter initializer scope. - -\commentary{ -This means that formal parameters, including initializing formals, must have distinct names, and that initializing formals are in scope for the initializer list, but they are not in scope for the body of the constructor. -When a formal parameter introduces a local variable into two scopes, it is still one variable and hence one storage location. -The type of the constructor is defined in terms of its formal parameters, including the initializing formals. -} - -\LMHash{}% -Initializing formals are executed during -the execution of generative constructors detailed below. -Executing an initializing formal \code{\THIS{}.\id} -causes the instance variable \id{} of the immediately surrounding class -to be assigned the value of the corresponding actual parameter, -% This can occur due to a failing implicit cast. -unless the assigned value has a dynamic type -which is not a subtype of the declared type of the instance variable \id{}, -in which case a dynamic error occurs. - -\commentary{ -The above rule allows initializing formals to be used as optional parameters: -} - -\begin{dartCode} -class A \{ - int x; - A([this.x]); -\} -\end{dartCode} - -\commentary{ -is legal, and has the same effect as -} - -\begin{dartCode} -class A \{ - int x; - A([int x]): this.x = x; -\} -\end{dartCode} - -\LMHash{}% -A \Index{fresh instance} is an instance whose identity is distinct from any previously allocated instance of its class. -A generative constructor always operates on a fresh instance of its immediately enclosing class. - -\commentary{ -The above holds if the constructor is actually run, as it is by \NEW{}. -If a constructor $c$ is referenced by \CONST{}, $c$ may not be run; instead, a canonical object may be looked up. -See the section on instance creation (\ref{instanceCreation}). -} - -\LMHash{}% -If a generative constructor $c$ is not a redirecting constructor and no body is provided, then $c$ implicitly has an empty body \code{\{\}}. - - -\paragraph{Redirecting Generative Constructors} -\LMLabel{redirectingGenerativeConstructors} - -\LMHash{}% -A generative constructor may be -\IndexCustom{redirecting}{constructor!redirecting}, -in which case its only action is to invoke another generative constructor. -A redirecting constructor has no body; -instead, it has a redirect clause that specifies which constructor the invocation is redirected to, and with which arguments. - -\begin{grammar} - ::= `:' \THIS{} (`.' )? -\end{grammar} - -\def\ConstMetavar{\mbox{\CONST{}?}} - -\LMHash{}% -Assume that -\code{$C$<$X_1\ \EXTENDS\ B_1 \ldots,\ X_m\ \EXTENDS\ B_m$>} -is the name and formal type parameters of the enclosing class, -$\ConstMetavar$ stands for either \CONST{} or nothing, -$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$, -and \id{} is an identifier. -Consider a declaration of a redirecting generative constructor $k$ of one of the forms - -\code{$\ConstMetavar$ $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1} = d_1 \ldots,\ T_{n+k}\ x_{n+k} = d_k$]): $R$;} - -\code{$\ConstMetavar$ $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1} = d_1 \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}): $R$;} - -\noindent -where $R$ is of one of the forms - -\code{$\THIS{}$($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)} - -\code{$\THIS{}.\id$($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)} - -\LMHash{}% -The -\IndexCustom{redirectee constructor}{constructor!redirectee} -for this declaration is then the constructor denoted by -\code{$C$<$X_1 \ldots,\ X_m$>} respectively \code{$C$<$X_1 \ldots,\ X_m$>.\id}. -It is a compile-time error if the static argument list type (\ref{actualArgumentLists}) of -\code{($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)} -is not an assignable match for the formal parameter list of the redirectee. - -\commentary{ -Note that the case where no named parameters are passed is covered by letting $q$ be zero, -and the case where $C$ is a non-generic class is covered by letting $m$ be zero, -in which case the formal type parameter list and actual type argument lists are omitted (\ref{generics}). -} - -\rationale{ -We require an assignable match rather than the stricter subtype match -because a generative redirecting constructor $k$ invokes its redirectee $k'$ -in a manner which resembles function invocation in general. -For instance, $k$ could accept an argument \code{x} -and pass on an expression $e_j$ using \code{x} such as \code{x.f(42)} to $k'$, -and it would be surprising -if $e_j$ were subject to more strict constraints than the ones applied to -actual arguments to function invocations in general. -} - -\LMHash{}% -When $\ConstMetavar$ is \CONST{}, -it is a compile-time error if the redirectee is not a constant constructor. -Moreover, when $\ConstMetavar$ is \CONST{}, each -$e_i,\ i \in 1 .. p+q$, -must be a potentially constant expression (\ref{constantConstructors}). - -\LMHash{}% -% This error can occur due to a failed implicit cast. -It is a dynamic type error if an actual argument passed -in an invocation of a redirecting generative constructor $k$ -is not a subtype of the actual type (\ref{actualTypeOfADeclaration}) -of the corresponding formal parameter in the declaration of $k$. -% This error can occur due to a failed implicit cast. -It is a dynamic type error if an actual argument passed -to the redirectee $k'$ of a redirecting generative constructor -is not a subtype of the actual type -(\ref{actualTypeOfADeclaration}) -of the corresponding formal parameter in the declaration of the redirectee. - - -\paragraph{Initializer Lists} -\LMLabel{initializerLists} - -\LMHash{}% -An initializer list begins with a colon, and consists of a comma-separated list of individual \Index{initializers}. - -\commentary{ -There are three kinds of initializers. -\begin{itemize} -\item[$\bullet$] A \emph{superinitializer} identifies a - \emph{superconstructor}\,---\,that is, - a specific constructor of the superclass. - Execution of the superinitializer causes - the initializer list of the superconstructor to be executed. -\item[$\bullet$] An \emph{instance variable initializer} - assigns a value to an individual instance variable. -\item[$\bullet$] An assertion. -\end{itemize} -} - -\begin{grammar} - ::= `:' (`,' )* - - ::= \SUPER{} - \alt \SUPER{} `.' - \alt - \alt - - ::= \gnewline{} - (\THIS{} `.')? `=' * -\end{grammar} - -\LMHash{}% -An initializer of the form \code{$v$ = $e$} is equivalent to -an initializer of the form \code{\THIS{}.$v$ = $e$}, -both forms are called \Index{instance variable initializers}. -It is a compile-time error if the enclosing class does not declare an instance variable named $v$. -Otherwise, let $T$ be the static type of $v$. -It is a compile-time error unless the static type of $e$ is assignable to $T$. - -\LMHash{}% -Consider a \Index{superinitializer} $s$ of the form - -\code{\SUPER{}($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -respectively - -\code{\SUPER{}.\id($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. - -\noindent{}% -Let $S$ be the superclass of the enclosing class of $s$. -It is a compile-time error if class $S$ does not declare a generative constructor named $S$ (respectively \code{$S$.\id}). -Otherwise, the static analysis of $s$ is performed as specified in Section~\ref{bindingActualsToFormals}, -as if \code{\SUPER{}} respectively \code{\SUPER{}.\id} -had had the function type of the denoted constructor, -%% TODO(eernst): The following is very imprecise, it just serves to remember -%% that we must specify how to deal with the type variables in that parameter -%% part. One thing that we weasel over is that the superclass may be a mixin -%% application. -and substituting the formal type variables of the superclass -for the corresponding actual type arguments passed to the superclass -in the header of the current class. - -\LMHash{}% -Let $k$ be a generative constructor. -Then $k$ may include at most one superinitializer in its initializer list or a compile-time error occurs. -If no superinitializer is provided, an implicit superinitializer of the form \SUPER{}() is added at the end of $k$'s initializer list, -unless the enclosing class is class \code{Object}. -It is a compile-time error if a superinitializer appears in $k$'s initializer list at any other position than at the end. -It is a compile-time error if more than one initializer corresponding to a given instance variable appears in $k$'s initializer list. -It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is initialized by means of an initializing formal of $k$. -It is a compile-time error if $k$'s initializer list contains an initializer for a final variable $f$ whose declaration includes an initialization expression. -It is a compile-time error if $k$ includes an initializing formal for a final variable $f$ whose declaration includes an initialization expression. - -\LMHash{}% -Let $f$ be a final instance variable declared in -the immediately enclosing class. -A compile-time error occurs unless $f$ is initialized -by one of the following means: -\begin{itemize} -\item $f$ is declared by an initializing variable declaration. -\item $f$ is initialized by means of an initializing formal of $k$. -\item $f$ has an initializer in $k$'s initializer list. -\end{itemize} - -\LMHash{}% -It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is not an instance variable declared in the immediately surrounding class. - -\commentary{ -The initializer list may of course contain an initializer for any instance variable declared by the immediately surrounding class, even if it is not final. -} - -\LMHash{}% -It is a compile-time error if a generative constructor of class \code{Object} includes a superinitializer. - - -\paragraph{Execution of Generative Constructors} -\LMLabel{executionOfGenerativeConstructors} - -\LMHash{}% -Execution of a generative constructor $k$ of type $T$ to initialize a fresh instance $i$ -is always done with respect to a set of bindings for its formal parameters -and the type parameters of the immediately enclosing class bound to -a set of actual type arguments of $T$, $t_1, \ldots, t_m$. - -\commentary{ -These bindings are usually determined by the instance creation expression that invoked the constructor (directly or indirectly). -However, they may also be determined by a reflective call. -} - -\LMHash{}% -If $k$ is redirecting then its redirect clause has the form - -\code{\THIS{}.$g$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - -where $g$ identifies another generative constructor of the immediately surrounding class. -Then execution of $k$ to initialize $i$ proceeds by evaluating the argument list -\code{($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -to an actual argument list $a$ of the form -\code{($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1}, \ldots,\ x_{n+k}$: $o_{n+k}$)} -in an environment where the type parameters of the enclosing class are bound to -$t_1, \ldots, t_m$. - -\LMHash{}% -Next, the body of $g$ is executed to initialize $i$ with respect to the bindings that map -the formal parameters of $g$ to the corresponding objects in the actual argument list $a$, -with \THIS{} bound to $i$, -and the type parameters of the immediately enclosing class bound to $t_1, \ldots, t_m$. - -\LMHash{}% -Otherwise, $k$ is not redirecting. -Execution then proceeds as follows: - -\LMHash{}% -The instance variable declarations of the immediately enclosing class -are visited in the order they appear in the program text. -For each such declaration $d$, if $d$ has the form -\code{\synt{finalConstVarOrType} $v$ = $e$; } -then $e$ is evaluated to an object $o$ -and the instance variable $v$ of $i$ is bound to $o$. - -\LMHash{}% -Any initializing formals declared in $k$'s parameter list are executed in the order they appear in the program text. -% In fact, this order is unobservable; this could be done any time prior to running the body, since -% these only effect \THIS{}. -Then, the initializers of $k$'s initializer list are executed to initialize $i$ -in the order they appear in the program, as described below -(p.\,\pageref{executionOfInitializerLists}). - -\rationale{ -We could observe the order by side effecting external routines called. -So we need to specify the order. -} - -\LMHash{}% -Then if any instance variable of $i$ declared by the immediately enclosing class -is not yet bound to an object, -all such variables are initialized with the null object (\ref{null}). - -\LMHash{}% -Then, unless the enclosing class is \code{Object}, the explicitly specified or -implicitly added superinitializer (\ref{initializerLists}) is executed to -further initialize $i$. - -\LMHash{}% -After the superinitializer has completed, the body of $k$ is executed in a scope where \THIS{} is bound to $i$. - -\rationale{ -This process ensures that no uninitialized final instance variable is ever seen by code. -Note that \THIS{} is not in scope on the right hand side of an initializer (see \ref{this}) so no instance method can execute during initialization: -an instance method cannot be directly invoked, -nor can \THIS{} be passed into any other code being invoked in the initializer. -} - - -\paragraph{Execution of Initializer Lists} -\LMLabel{executionOfInitializerLists} - -\LMHash{}% -During the execution of a generative constructor to initialize an instance $i$, -execution of an initializer of the form \code{\THIS{}.$v$ = $e$} -proceeds as follows: - -\LMHash{}% -First, the expression $e$ is evaluated to an object $o$. -Then, the instance variable $v$ of $i$ is bound to $o$. -% This error can occur due to an implicit cast. -It is a dynamic type error if the dynamic type of $o$ is not -a subtype of the actual type -(\ref{actualTypeOfADeclaration}) -of the instance variable $v$. - -\LMHash{}% -Execution of an initializer that is an assertion proceeds by executing the assertion (\ref{assert}). - -\LMHash{}% -Consider a superinitializer $s$ of the form - -\code{\SUPER{}($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -respectively - -\code{\SUPER{}.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. - -\LMHash{}% -Let $C$ be the class in which $s$ appears and let $S$ be the superclass of $C$. -If $S$ is generic (\ref{generics}), -let $u_1, \ldots, u_p$ be the actual type arguments passed to $S$, -obtained by substituting $t_1, \ldots, t_m$ -for the formal type parameters of $C$ -in the superclass as specified in the header of $C$, and -$t_1, \ldots, t_m$ -are the actual bindings of the type variables of $C$. -Let $k$ be the constructor declared in $S$ and named -$S$ respectively \code{$S$.\id}. - -\LMHash{}% -Execution of $s$ proceeds as follows: -The argument list -\code{($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -is evaluated to an actual argument list $a$ of the form -\code{($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1}, \ldots,\ x_{n+k}$: $o_{n+k}$)}. -Then the body of the superconstructor $k$ is executed -in an environment where the formal parameters of $k$ are bound to -the corresponding actual arguments from $a$, -and the formal type parameters of $S$ are bound to $u_1, \ldots, u_p$. - - -\subsubsection{Factories} -\LMLabel{factories} - -\LMHash{}% -A \IndexCustom{factory}{constructor!factory} -is a constructor prefaced by the built-in identifier -(\ref{identifierReference}) -\FACTORY{}. - -\begin{grammar} - ::= \gnewline{} - \FACTORY{} (`.' )? -\end{grammar} - -%The enclosing scope of a factory constructor is the static scope \ref{} of the class in which it is declared. - -\LMHash{}% -The return type of a factory whose signature is of the form \FACTORY{} $M$ or the form \FACTORY{} \code{$M$.\id} is $M$ if $M$ is not a generic type; -otherwise the return type is \code{$M$<$T_1, \ldots,\ T_n$>} where $T_1, \ldots, T_n$ are the type parameters of the enclosing class. - -\LMHash{}% -It is a compile-time error if $M$ is not the name of the immediately enclosing class. - -\LMHash{}% -% This error can occur due to an implicit cast. -It is a dynamic type error if a factory returns a non-null object -whose type is not a subtype of its actual -(\ref{actualTypeOfADeclaration}) -return type. - -\rationale{ -It seems useless to allow a factory to return the null object (\ref{null}). -But it is more uniform to allow it, as the rules currently do. -} - -\rationale{ -Factories address classic weaknesses associated with constructors in other languages. -Factories can produce instances that are not freshly allocated: they can come from a cache. -Likewise, factories can return instances of different classes. -} - - -\paragraph{Redirecting Factory Constructors} -\LMLabel{redirectingFactoryConstructors} - -\LMHash{}% -A \IndexCustom{redirecting factory constructor}{constructor!redirecting factory} -specifies a call to a constructor of another class that is to be used -whenever the redirecting constructor is called. - -\begin{grammar} - ::= \gnewline{} - \CONST{}? \FACTORY{} (`.' )? `=' - \gnewline{} (`.' )? -\end{grammar} - -Assume that -\code{$C$<$X_1\ \EXTENDS\ B_1 \ldots,\ X_m\ \EXTENDS\ B_m$>} -is the name and formal type parameters of the enclosing class, -$\ConstMetavar$ is \CONST{} or empty, -$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$, -$T$ is a type name, and \id{} is an identifier, -then consider a declaration of a redirecting factory constructor $k$ of one of the forms - -\begin{normativeDartCode} -$\ConstMetavar$ \FACTORY{} - $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$]) = $R$; -\\ -$\ConstMetavar$ \FACTORY{} - $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$\}) = $R$; -\end{normativeDartCode} - -\noindent -where $R$ is of one of the forms -\code{$T$<$S_1 \ldots,\ S_p$>} or -\code{$T$<$S_1 \ldots,\ S_p$>.\id}. - -\LMHash{}% -It is a compile-time error if $T$ does not denote -a class accessible in the current scope. -If $T$ does denote such a class $D$, -it is a compile-time error if $R$ does not denote a constructor. -% It is by induction sufficient to check for abstractness one level down, -% because it is an error on the redirectee if this occurs after multiple -% redirections: -Otherwise, it is a compile-time error -if $R$ denotes a generative constructor and $D$ is abstract. -Otherwise, the -\IndexCustom{redirectee constructor}{constructor!redirectee} -for this declaration is the constructor denoted by $R$. - -\LMHash{}% -A redirecting factory constructor $q'$ is \Index{redirection-reachable} -from a redirecting factory constructor $q$ if{}f -$q'$ is the redirectee constructor of $q$, -or $q''$ is the redirectee constructor of $q$ -and $q'$ is redirection-reachable from $q''$. -It is a compile-time error if a redirecting factory constructor -is redirection-reachable from itself. - -\LMHash{}% -Let $\argumentList{T}$ be the static argument list type (\ref{actualArgumentLists}) -\code{($T_1 \ldots,\ T_{n+k}$)} -when $k$ takes no named arguments, and -\code{($T_1 \ldots,\ T_n,\ T_{n+1}\ x_{n+1},\ \ldots,\ T_{n+k}\ x_{n+k}$)} -when $k$ takes some named arguments. -It is a compile-time error if $\argumentList{T}$ -is not a subtype match for the formal parameter list of the redirectee. - -\rationale{ -We require a subtype match -(rather than the more forgiving assignable match -which is used with a generative redirecting constructor), -because a factory redirecting constructor $k$ always invokes -its redirectee $k'$ with -exactly the same actual arguments that $k$ received. -This means that a downcast on an actual argument -``between'' $k$ and $k'$ -would either be unused because the actual argument has -the type required by $k'$, -or it would amount to a dynamic error which is simply delayed a single step. -} - -\commentary{ -Note that the non-generic case is covered by letting $m$ or $p$ or both be zero, -in which case the formal type parameter list of the class $C$ -and/or the actual type argument list of the redirectee constructor is omitted (\ref{generics}). -} - -\LMHash{}% -It is a compile-time error if $k$ explicitly specifies a default value for an optional parameter. - -\rationale{% -Default values specified in $k$ would be ignored, -since it is the \emph{actual} parameters that are passed to $k'$. -Hence, default values are disallowed.% -} - -\LMHash{}% -It is a compile-time error if a formal parameter of $k'$ has a default value -whose type is not a subtype of the type annotation -on the corresponding formal parameter in $k$. - -\commentary{ -Note that it is not possible to modify the arguments being passed to $k'$. -} - -\rationale{ -At first 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: -\begin{itemize} -\item An abstract class may provide a constant constructor that utilizes the constant constructor of another class. -\item A redirecting factory constructor avoids the need for forwarders to repeat the formal parameters and their default values. -\end{itemize} -} - -\LMHash{}% -It is a compile-time error if $k$ is prefixed with the \CONST{} modifier but $k'$ is not a constant constructor (\ref{constantConstructors}). - -\LMHash{}% -Let $T_1, \ldots, T_m$ be the actual type arguments passed to $k'$ -in the declaration of $k$. -Let $X_1, \ldots, X_m$ be the formal type arguments declared by -the class that contains the declaration of $k'$. -Let $F'$ be the function type of $k'$ (\ref{constructors}). -It is a compile-time error if $[T_1/X_1, \ldots, T_m/X_m]F'$ -is not a subtype of the function type of $k$. - -\commentary{ -In the case where the two classes are non-generic -this is just a subtype check on the function types of the two constructors. -In general, this implies that the resulting object conforms to -the interface of the immediately enclosing class of $k$. -} - -\LMHash{}% -For the dynamic semantics, -assume that $k$ is a redirecting factory constructor -and $k'$ is the redirectee of $k$. - -\LMHash{}% -% This error can occur due to an implicit cast. -It is a dynamic type error if an actual argument passed in an invocation of $k$ -is not a subtype of the actual type (\ref{actualTypeOfADeclaration}) -of the corresponding formal parameter in the declaration of $k$. - -\LMHash{}% -When the redirectee $k'$ is a factory constructor, -execution of $k$ amounts to execution of $k'$ with the actual arguments passed to $k$. -The result of the execution of $k'$ is the result of $k$. - -\LMHash{}% -When the redirectee $k'$ is a generative constructor, -let $o$ be a fresh instance (\ref{generativeConstructors}) -of the class that contains $k'$. -Execution of $k$ then amounts to execution of $k'$ to initialize $o$, -governed by the same rules as an instance creation expression (\ref{instanceCreation}). -If $k$ completed normally then the execution of $k'$ completes normally returning $o$, -otherwise $k'$ completes by throwing the exception and stack trace thrown by $k$. - - -\subsubsection{Constant Constructors} -\LMLabel{constantConstructors} - -\LMHash{}% -A \IndexCustom{constant constructor}{constructor!constant} -may be used to create compile-time constant (\ref{constants}) objects. -A constant constructor is prefixed by the reserved word \CONST{}. - -\begin{grammar} - ::= \CONST{} -\end{grammar} - -%\commentary{Spell out subtleties: a constant constructor call within the initializer of a constant constructor is treated as a ordinary constructor call (a new), because the arguments cannot be assumed constant anymore. In practice, this means two versions are compiled and analyzed. One for new and one for const.} - -\commentary{ -All the work of a constant constructor must be handled via its initializers. -} - -\LMHash{}% -It is a compile-time error if a constant constructor is declared by a class that has a mutable instance variable. - -\commentary{ -The above refers to both locally declared and inherited instance variables. -} - -\LMHash{}% -It is a compile-time error if a constant constructor is declared by a class $C$ if any instance variable declared in $C$ is initialized with an expression that is not a constant expression. - -\commentary{ -A superclass of $C$ cannot declare such an initializer either, because it must necessarily declare constant constructor as well (unless it is \code{Object}, which declares no instance variables). -} - -\LMHash{}% -The superinitializer that appears, explicitly or implicitly, in the initializer list of a constant constructor must specify a constant constructor of the superclass of the immediately enclosing class or a compile-time error occurs. - -\LMHash{}% -Any expression that appears within the initializer list of a constant constructor must be a potentially constant expression, or a compile-time error occurs. - -\LMHash{}% -A \Index{potentially constant expression} is an expression $e$ that could be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants of appropriate types, and where $e$ is also a valid expression if all the formal parameters are treated as non-constant variables. - -\commentary{ -The difference between a potentially constant expression and a constant expression (\ref{const}) deserves some explanation. - -The key issue is how one treats the formal parameters of a constructor. - -If a constant constructor is invoked from a constant object expression, the actual arguments will be required to be constant expressions. -Therefore, if we were assured that constant constructors were always invoked from constant object expressions, we could assume that the formal parameters of a constructor were compile-time constants. - -However, constant constructors can also be invoked from ordinary instance creation expressions (\ref{new}), and so the above assumption is not generally valid. - -Nevertheless, the use of the formal parameters of a constant constructor within the constructor is of considerable utility. -The concept of potentially constant expressions is introduced to facilitate limited use of such formal parameters. -Specifically, we allow the usage of the formal parameters of a constant constructor for expressions that involve built-in operators, but not for constant objects, lists and maps. -This allows for constructors such as: -} - -\begin{dartCode} -\CLASS{} C \{ - \FINAL{} x; \FINAL{} y; \FINAL{} z; - \CONST{} C(p, q): x = q, y = p + 100, z = p + q; -\} -\end{dartCode} - -\commentary{ -The assignment to \code{x} is allowed under the assumption that \code{q} is constant (even though \code{q} is not, in general a compile-time constant). -The assignment to \code{y} is similar, but raises additional questions. -In this case, the superexpression of \code{p} is \code{p + 100}, and it requires that \code{p} be a numeric constant expression for the entire expression to be considered constant. -The wording of the specification allows us to assume that \code{p} evaluates to an integer. -A similar argument holds for \code{p} and \code{q} in the assignment to \code{z}. - -However, the following constructors are disallowed: -} - -\begin{dartCode} -\CLASS{} D \{ - \FINAL{} w; - \CONST{} D.makeList(p): w = \CONST{} [p]; // \comment{compile-time error} - \CONST{} D.makeMap(p): w = \CONST{} \{"help": q\}; // \comment{compile-time error} - \CONST{} D.makeC(p): w = \CONST{} C(p, 12); // \comment{compile-time error} -\} -\end{dartCode} - -\commentary{ -The problem is not that the assignments to \code{w} are not potentially constant; they are. -However, all these run afoul of the rules for constant lists (\ref{lists}), maps (\ref{maps}) and objects (\ref{const}), all of which independently require their subexpressions to be constant expressions. -} - -\rationale{ -All of the illegal constructors of \code{D} above could not be sensibly invoked via \NEW{}, because an expression that must be constant cannot depend on a formal parameter, which may or may not be constant. -In contrast, the legal examples make sense regardless of whether the constructor is invoked via \CONST{} or via \NEW{}. - -Careful readers will of course worry about cases where the actual arguments to \code{C()} are constants, but are not numeric. -This is precluded by the following rule, combined with the rules for evaluating constant objects (\ref{const}). -} - -\LMHash{}% -When a constant constructor $k$ is invoked from a constant object expression, -it is a compile-time error if -the invocation of $k$ at run time would throw an exception, -and it is a compile-time error if -substitution of the actual arguments for the formal parameters -yields an initializing expression $e$ in the initializer list of $k$ -which is not a constant expression. - -\commentary{ -For instance, if $e$ is \code{a.length} -where \code{a} is a formal argument of $k$ with type \DYNAMIC{}, -$e$ is potentially constant and can be used in the initializer list of $k$. -It is an error to invoke $k$ with an argument of type \code{C} -if \code{C} is a class different from \code{String}, -even if \code{C} has a \code{length} getter, -and that same expression would evaluate without errors at run time. -} - -%Discuss External Constructors in ne subsubsection here - - -\subsection{Static Methods} -\LMLabel{staticMethods} - -\LMHash{}% -\IndexCustom{Static methods}{method!static} -are functions, other than getters or setters, whose declarations are immediately contained within a class declaration and that are declared \STATIC{}. -The static methods of a class $C$ are those static methods declared by $C$. - -\rationale{ -Inheritance of static methods has little utility in Dart. -Static methods cannot be overridden. -Any required static function can be obtained from its declaring library, -and there is no need to bring it into scope via inheritance. -Experience shows that developers are confused by -the idea of inherited methods that are not instance methods. - -Of course, the entire notion of static methods is debatable, -but it is retained here because so many programmers are familiar with it. -Dart static methods may be seen as functions of the enclosing library. -} - -\commentary{ -Static method declarations may conflict with other declarations -(\ref{classMemberConflicts}). -} - - -\subsection{Superclasses} -\LMLabel{superclasses} - -%% TODO(eernst): We need to say that the superclass which is obtained -%% by mixin application is generic when $C$ is generic, or at least -%% when one or more of $C$'s type variables are used by the classes -%% in the \EXTENDS{} or \WITH{} clause of $C$. It says below that -%% these clauses are in the type parameter scope of $C$, but that does -%% not allow us to talk about the superclass as an actual, stand-alone -%% class (unless we start defining nested classes, such that the -%% superclass can be declared in that scope). - -\LMHash{}% -The superclass $S'$ of a class $C$ whose declaration has a with clause -\code{\WITH{} $M_1, \ldots,\ M_k$} -and an extends clause -\code{\EXTENDS{} $S$} -is the abstract class obtained by application of -mixin composition (\ref{mixins}) $M_k* \cdots * M_1$ to $S$. -The name $S'$ is a fresh identifier. -If no \WITH{} clause is specified then the \EXTENDS{} clause of -a class $C$ specifies its superclass. -If no \EXTENDS{} clause is specified, then either: -\begin{itemize} -\item $C$ is \code{Object}, which has no superclass. OR -\item Class $C$ is deemed to have an \EXTENDS{} clause of the form -\code{\EXTENDS{} Object}, and the rules above apply. -\end{itemize} - -\LMHash{}% -It is a compile-time error to specify an \EXTENDS{} clause -for class \code{Object}. - -\begin{grammar} - ::= \EXTENDS{} ? - \alt - - ::= \WITH{} -\end{grammar} - -%The superclass clause of a class C is processed within the enclosing scope of the static scope of C. -%\commentary{ -%This means that in a generic class, the type parameters of the generic are available in the superclass clause. -%} - -\LMHash{}% -The scope of the \EXTENDS{} and \WITH{} clauses of a class $C$ is the type-parameter scope of $C$. - -\LMHash{}% -It is a compile-time error if the type in the \EXTENDS{} clause of a class $C$ is -a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}), -an enumerated type (\ref{enums}), -a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}), -or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). - -\commentary{% -Note that \VOID{} is a reserved word, -which implies that the same restrictions apply for the type \VOID, -and similar restrictions are specified for other types like -\code{Null} (\ref{null}) and -\code{String} (\ref{strings}).% -} - -\commentary{% -The type parameters of a generic class are available in the lexical scope of the superclass clause, potentially shadowing classes in the surrounding scope. -The following code is therefore illegal and should cause a compile-time error: -} - -\begin{dartCode} -class T \{\} -\\ -/* Compilation error: Attempt to subclass a type parameter */ -class G extends T \{\} -\end{dartCode} - -\LMHash{}% -%% TODO(eernst): Consider replacing all occurrences of `a superclass` -%% by `a direct or indirect superclass`, because it's too confusing. -A class $S$ is a \Index{superclass} of a class $C$ if{}f either: -\begin{itemize} -\item $S$ is the superclass of $C$, or -\item $S$ is a superclass of a class $S'$, -and $S'$ is the superclass of $C$. -\end{itemize} - -\LMHash{}% -It is a compile-time error if a class $C$ is a superclass of itself. - - -\subsubsection{Inheritance and Overriding} -\LMLabel{inheritanceAndOverriding} - -\LMHash{}% -Let $C$ be a class, let $A$ be a superclass of $C$, and -let $S_1, \ldots, S_k$ be superclasses of $C$ that are also subclasses of $A$. -$C$ \Index{inherits} all concrete, accessible instance members of $A$ -that have not been overridden by a concrete declaration in $C$ or in at least one of $S_1, \ldots, S_k$. - -\rationale{ -It would be more attractive to give a purely local definition 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 different library $L_2$, -but the superclass chain of $S$ includes a class declared in $L_1$. -} - -\LMHash{}% -A class may override instance members that would otherwise have been inherited from its superclass. - -\LMHash{}% -Let $C = S_0$ be a class declared in library $L$, and -let $\{S_1, \ldots, S_k\}$ be the set of all superclasses of $C$, -where $S_i$ is the superclass of $S_{i-1}$ for $i \in 1 .. k$. -\commentary{$S_k$ is the built-in class \code{Object}.} -Let $C$ declare a concrete member $m$, and -let $m'$ be a concrete member of $S_j, j \in 1 .. k$, that has the same name as $m$, -such that $m'$ is accessible to $L$. -Then $m$ overrides $m'$ -if $m'$ is not already overridden by a concrete member of at least one of $S_1, \ldots, S_{j-1}$ -and neither $m$ nor $m'$ are instance variables. - -\commentary{ -Instance variables never override each other. -The getters and setters induced by instance variables do. -} - -\rationale{ -Again, a local definition of overriding would be preferable, -but fails to account for library privacy. -} - -\commentary{ -Whether an override is legal or not is specified relative to -all direct superinterfaces, not just the interface of the superclass, -and that is described elsewhere -(\ref{instanceMethods}). -Static members never override anything, -but they may participate in some conflicts -involving declarations in superinterfaces -(\ref{classMemberConflicts}). -} - -\commentary{ -For convenience, here is a summary of the relevant rules, -using `error' to denote compile-time errors. -Remember that this is not normative. -The controlling language is in the relevant sections of the specification. - -\begin{enumerate} - -\item There is only one namespace - for getters, setters, methods and constructors (\ref{scoping}). - An instance or static variable $f$ introduces a getter $f$, - and a mutable instance or static variable $f$ also introduces a setter - \code{$f$=} (\ref{instanceVariables}, \ref{variables}). - When we speak of members here, we mean - accessible instance or static variables, getters, setters, and methods - (\ref{classes}). -\item You cannot have two members with the same name in the same class---be - they declared or inherited (\ref{scoping}, \ref{classes}). -\item Static members are never inherited. -\item It is an error if you have a static member named $m$ in your class - and an instance member of the same name (\ref{classMemberConflicts}). -\item It is an error if you have a static setter \code{$v$=}, - and an instance member $v$ (\ref{setters}). -\item It is an error if you have a static getter $v$ - and an instance setter \code{$v$=} (\ref{getters}). -\item If you define 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. -\item \label{typeSigAssignable} - If two members override each other, - it is an error unless it is a correct override - (\ref{correctMemberOverrides}). -\item Setters, getters and operators never have - optional parameters of any kind; - it's an error (\ref{operators}, \ref{getters}, \ref{setters}). -\item - It is an error if a member has the same name as its enclosing class - (\ref{classes}). -\item A class has an implicit interface (\ref{classes}). -\item Superinterface members are not inherited by a class, - but are inherited by its implicit interface. - Interfaces have their own inheritance rules - (\ref{interfaceInheritanceAndOverriding}). -\item A member is abstract if - it has no body and is not labeled \EXTERNAL{} - (\ref{abstractInstanceMembers}, \ref{externalFunctions}). -\item A class is abstract if{}f it is explicitly labeled \ABSTRACT{}. -\item It is an error if a concrete class does not implement some member - of its interface, and there is no non-trivial \code{noSuchMethod} - (\ref{classes}). -\item It is an error to call a non-factory constructor of an abstract class - using an instance creation expression (\ref{instanceCreation}), - such a constructor may only be invoked from another constructor - using a super invocation (\ref{superInvocation}). -\item If a class defines an instance member named $m$, - and any of its superinterfaces have a member signature named $m$, - the interface of the class contains the $m$ from the class itself. -\item An interface inherits all members of its superinterfaces - that are not overridden and not members of multiple superinterfaces. -\item If multiple superinterfaces of an interface - define a member with the same name as $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, an error occurs - (\ref{interfaceInheritanceAndOverriding}). -\item Rule \ref{typeSigAssignable} applies to interfaces as well as classes - (\ref{interfaceInheritanceAndOverriding}). -\item It is an error if a concrete class does not have an implementation - for a method in its interface - unless it has a non-trivial \code{noSuchMethod} - (\ref{theMethodNoSuchMethod}). -\item The identifier of a named constructor cannot be - the same as the name of a static member declared in the same class - (\ref{classMemberConflicts}). -\end{enumerate} -} - - -\subsection{Superinterfaces} -\LMLabel{superinterfaces} - -\LMHash{}% -A class has a set of \Index{direct superinterfaces}. -This set contains the interface of its superclass -and the interfaces of the classes specified in -the \IMPLEMENTS{} clause of the class. - -\begin{grammar} - ::= \IMPLEMENTS{} -\end{grammar} - -\LMHash{}% -The scope of the \IMPLEMENTS{} clause of a class $C$ is the type-parameter scope of $C$. - -\LMHash{}% -It is a compile-time error if an element in the type list of the \IMPLEMENTS{} clause of a class $C$ is -a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}), -an enumerated type (\ref{enums}), -a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}), -or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). -It is a compile-time error if two elements in the type list of the \IMPLEMENTS{} clause of a class $C$ specifies the same type $T$. -It is a compile-time error if the superclass of a class $C$ is one of the elements of the type list of the \IMPLEMENTS{} clause of $C$. -It is a compile-time error if a class $C$ has two superinterfaces that are different instantiations of the same generic class. -\commentary{For example, a class may not have both `List` and `List` as superinterfaces.} -% If we need to allow multiple instantiations, they'll need to have a most -% specific one, and then we can add the following clause -%, unless it implements one that is a subtype of all the other. \commentary{This ensures that each class implements one {\em most specific} version of a generic class' interface.} - -\rationale{ -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. -} - -\LMHash{}% -It is a compile-time error if the interface of a class $C$ is a superinterface of itself. - -\commentary{ -A class does not inherit members from its superinterfaces. -However, its implicit interface does. -} - - -\subsection{Class Member Conflicts} -\LMLabel{classMemberConflicts} - -\LMHash{}% -Some pairs of class member declarations cannot coexist, -even though they do not both introduce the same name into the same scope. -This section specifies these errors. - -\LMHash{}% -The \Index{basename} of a getter or method named $n$ is $n$; -the basename of a setter named \code{$n$=} is $n$. - -\LMHash{}% -Let $C$ be a class. -It is a compile-time error if $C$ -declares a constructor named \code{$C$.$n$} and -a static member with basename $n$. -It is a compile-time error if $C$ -declares a static member with basename $n$ and -the interface of $C$ has an instance member with basename $n$. -It is a compile-time error if the interface of $C$ -has a method named $n$ and a setter with basename $n$. - -\LMHash{}% -These errors occur when the getters or setters are defined explicitly -as well as when they are induced by variable declarations. - -\commentary{% -Note that other errors which are similar in nature are covered elsewhere. -For instance, if $C$ is a class that has two superinterfaces $I_1$ and $I_2$, -where $I_1$ has a method named $m$ -and $I_2$ has a getter named $m$, -then it is an error because the computation of the interface of $C$ -includes a computation of the combined member signature -(\ref{combinedMemberSignatures}) -of that getter and that method, -and it is an error for a combined member signature -to include a getter and a non-getter. -} - - -\section{Interfaces} -\LMLabel{interfaces} - -\LMHash{}% -This section introduces the notion of interfaces. -We define the notion of member signatures first, -because that concept is needed in the definition of interfaces. - -% We need a separate concept of instance member signatures, -% such that we can obtain a clean treatment of how to compute -% the interface of a class and the common interface of a set -% of superinterfaces, e.g., the superinterfaces of a class or -% the common interface represented by an `on` clause in a -% `mixin`. For instance, we do not want to specify each time -% we check for conflicts that the body doesn't matter, or -% that the metadata doesn't matter, the interface of a class -% should simply never contain a body of any member in the -% first place. Also the clear separation of a syntactic -% declaration and a member signature provides a well-defined -% occasion to introduce transformations, e.g., to replace -% some parameter types by others, which is needed for the -% specification of a correct override relation. - -\LMHash{}% -A \Index{member signature} $s$ -can be derived from a class instance member declaration $D$. -It contains the same information as $D$, -except that $s$ omits the body, if any; -it contains the return type and parameter types -even if they are implicit in $D$; -it omits the names of positional parameters; -it omits the modifier \FINAL{} from each parameter, if any; -it omits metadata -(\ref{metadata}); -and it omits information about whether the member is -\EXTERNAL{}, \ASYNC{}, \ASYNC*, or \SYNC*. -It makes no difference whether $D$ is given as explicit syntax -or it is induced implicitly, e.g., by a variable declaration. -Finally, if $s$ has formal parameters, -each of them has the modifier \COVARIANT{} -(\ref{requiredFormals}) -if and only if that parameter is covariant-by-declaration -(\ref{covariantParameters}). - -\LMHash{}% -We use a syntax similar to that of an abstract member declaration -to specify member signatures. -The difference is that the names of positional parameters are omitted. -This syntax is only used for the purposes of specification. - -\rationale{ -Member signatures are synthetic entities, that is, -they are not supported as concrete syntax in a Dart program, -they are computed entities used during static analysis. -However, it is useful to be able to indicate the -properties of a member signature in this specification -via a syntactic representation. -A member signature makes it explicit -whether a parameter is covariant-by-declaration, -but it remains implicit whether it is covariant-by-class -(\ref{covariantParameters}). -The reason for this is that the rule for determining whether -a given override relation is correct -(\ref{correctMemberOverrides}) -depends on the former and not on the latter. -} - -\LMHash{}% -Let $m$ be a method signature of the form - -\noindent -\code{$T_0$ \id<\TypeParametersStd>(} - -\noindent -\code{\qquad\qquad\List{\COVARIANT{}?\ T}{1}{n},} - -\noindent -\code{\qquad\qquad[\PairList{\COVARIANT{}?\ T}{= d}{n+1}{n+k}])}. - -\noindent -The \IndexCustom{function type of}{method signature!function type} -$m$ is then - -\noindent -\FunctionTypePositionalStd{T_0}. - -\LMHash{}% -Let $m$ be a method signature of the form - -\noindent -\code{$T_0$ \id<\TypeParametersStd>(} - -\noindent -\code{\qquad\qquad\List{\COVARIANT{}?\ T}{1}{n},} - -\noindent -\code{\qquad\qquad\{\TripleList{\COVARIANT{}?\ T}{x}{= d}{n+1}{n+k}\})}. - -\noindent -The \NoIndex{function type of} $m$ is then - -\noindent -\FunctionTypeNamedStd{T_0}. - -\LMHash{}% -Let $m$ be a setter signature of the form -\code{\VOID\ \SET\ \id(\COVARIANT?\ $T$ $p$)}. -The \NoIndex{function type of} $m$ is then -\FunctionTypeSimple{\VOID}{$T$}. - -\LMHash{}% -The function type of a member signature remains unchanged if -some or all default values are omitted. - -\commentary{ -We do not specify the function type of a getter signature. -For such signatures we will instead directly refer to the return type. -} - -\LMHash{}% -An \Index{interface} is a synthetic entity that defines -how one may interact with an object. -An interface has method, getter and setter signatures, -and a set of superinterfaces, -which are again interfaces. -Each interface is the implicit interface of a class, -in which case we call it a -\IndexCustom{class interface}{interface!class}, -or a combination of several other interfaces, -in which case we call it a -\IndexCustom{combined interface}{interface!combined}. - -\LMHash{}% -Let $C$ be a class. -The \Index{class interface} $I$ of $C$ is the interface that declares -a member signature derived from -each instance member declared by $C$. -The \Index{direct superinterfaces} of $I$ are the direct superinterfaces of $C$ -(\ref{superinterfaces}). - -\commentary{ -We say that the class interface 'declares' these member signatures, -such that we can say that an interface 'declares' or 'has' a member, -just like we do for classes. -Note that a member signature $s$ of the interface of class $C$ -may have a parameter $p$ with modifier \COVARIANT{}, -even though $s$ was derived from a declaration $D$ in $C$ -and the parameter corresponding to $p$ in $D$ does not -have that modifier. -This is because $p$ may have ``inherited'' -the property of being covariant-by-declaration -from one of its superinterfaces -(\ref{covariantParameters}). -} - -\LMHash{}% -%% TODO(eernst): 'list of interfaces' --> 'set of interfaces' if we -%% switch to use a total order on top types for interface specificity. -The \Index{combined interface} $I$ of a list of interfaces \List{I}{1}{k} -is the interface that declares the set of member signatures $M$, -where $M$ is determined as specified below. -The \Index{direct superinterfaces} of $I$ is the set \List{I}{1}{k}. - -\LMHash{}% -Let $M_0$ be the set of all member signatures declared by \List{I}{1}{k}. -$M$ is then the smallest set satisfying the following: - -\begin{itemize} -\item For each name \id{} and library $L$ such that $M_0$ contains - a member signature named \id{} which is accessible to $L$, - let $m$ be the combined member signature named \id{} - from \List{I}{1}{k} with respect to $L$. - It is a compile-time error - if the computation of this combined member signature failed. - Otherwise, $M$ contains $m$. -\end{itemize} - -\rationale{ -Interfaces must be able to contain inaccessible member signatures, -because they may be accessible from the interfaces associated with -declarations of subtypes. -} - -\commentary{% -For instance, class $C$ in library $L$ may declare a private member named -\code{\_foo}, -a class $D$ in a different library $L_2$ may extend $C$, -and a class $E$ in library $L$ may extend $D$; -$E$ may then declare a member that overrides \code{\_foo} from $C$, -and that override relation must be checked based on the interface of $D$. -So we cannot allow the interface of $D$ -to ``forget'' inaccessible members like \code{\_foo}. - -For conflicts the situation is even more demanding: -Classes $C_1$ and $C_2$ in library $L$ may declare private members -\code{String \_foo(int i)} and \code{int get \_foo}, -and a subtype $D_{12}$ in a different library $L_2$ may have -an \IMPLEMENTS{} clause listing both $C_1$ and $C_2$. -In that case we must report a conflict even though the conflicting -declarations are not accessible to $L_2$, -because those member signatures are then noSuchMethod forwarded -(\ref{theMethodNoSuchMethod}), -and an invocation of \code{\_foo} on an instance of $D$ in $L$ -must return an `int` according to the first member signature, -and it must return a function object according to the second one, -and an invocation of \code{\_foo(42)} -must return a \code{String} with the first member signature, and it must fail -(at compile time or, for a dynamic invocation, run time) with the second. -} - -\rationale{% -It may not be possible to satisfy such constraints simultaneously, -and it will inevitably be a complex semantics, -so we have chosen to make it an error. -It is unfortunate that the addition of a private declaration -in one library may break existing code in a different library. -But it should be noted that the conflicts can be detected locally -in the library where the private declarations exist, -because they only arise for private members with -the same name and incompatible signatures. -Renaming that private member to anything not used in that library -will eliminate the conflict and will not break any clients. -} - - -\subsection{Combined Member Signatures} -\LMLabel{combinedMemberSignatures} - -\LMHash{}% -This section specifies how to compute a member signature which will -appropriately stand for a prioritized set of several member signatures, -taken from a given list of interfaces. - -\commentary{ -In general, a combined member signature has a type which is -a subtype of all the types given for that member. -This is needed in order to ensure that the type of -a member \id{} of a class $C$ is well-defined, -even in the case where $C$ inherits -several different declarations of \id{} -and does not override \id{}. -In case of failure, it serves to specify the situations -where a developer must add a declaration in order to resolve an ambiguity. -The member signatures are prioritized in the sense that we will select -a member signature from the interface with the lowest possible index -in the case where several member signatures are equally suitable -to be chosen as the combined member signature. -That is, ``the first interface wins''. -} - -\LMHash{}% -For the purposes of computing a combined member signature, -we need a special notion of -\IndexCustom{equality}{member signature equality} -of member signatures. -Two member signatures $m_1$ and $m_2$ are equal -if{}f they have the same name, -are accessible to the same set of libraries, -have the same same return type (for getters), -or the same function type and the same occurrences of \COVARIANT{} -(for methods and setters). - -\commentary{ -In particular, private methods from different libraries are never equal. -Top types differ as well. -For instance, -\FunctionTypeSimple{\DYNAMIC}{} and \FunctionTypeSimple{\code{Object}}{} -are not equal, even though they are subtypes of each other. -We need this distinction because management of top type discrepancies is -one of the purposes of computing a combined interface. -} - -\LMHash{}% -Now we define combined member signatures. -Let \id{} be an identifier, $L$ a library, -\List{I}{1}{k} a list of interfaces, -and $M_0$ the set of -all member signatures from \List{I}{1}{k} named \id{} -and accessible to $L$. -The -\IndexCustom{combined member signature - named \id{} from \List{I}{1}{k} with respect to $L$}{% - combined member signature} -is the member signature which is obtained as follows: - -\LMHash{}% -If $M_0$ is empty, computation of the combined member signature failed. - -\LMHash{}% -If $M_0$ contains exactly one member signature $m'$, -the combined member signature is $m'$. - -\LMHash{}% -Otherwise, $M_0$ contains more than one member signature \List{m}{1}{q}. - -\LMHash{}% -\Case{Failing mixtures} -If $M_0$ contains at least one getter signature -and at least one non-getter signature, -the computation of the combined member signature failed. -\EndCase - -\LMHash{}% -\Case{Getters} -If $M_0$ contains getter signatures only, -the computation of the combined member signature proceeds as described below -for methods and setters, -except that it uses the return type of the getter signature -where methods and setters use the function type of the member signature. -\EndCase - -\LMHash{}% -\Case{Methods and setters} -In this case $M_0$ consists of setter signatures only, -or method signatures only, -because the name \id{} in the former case always ends in \lit{=}, -which is never true in the latter case. - -\LMHash{}% -Determine whether there exists a non-empty set $N \subseteq 1 .. q$ such that -for each $i \in N$, -the function type of $m_i$ is a subtype of -the function type of $m_j$ for each $j \in 1 .. q$. -% -If no such set exists, the computation of the combined member signature failed. -\commentary{% -A useful intuition about this situation is that -the given member signatures do not agree on -which type is suitable for the member named \id. -Otherwise we have a set of member signatures which are ``most specific'' -in the sense that their function types are subtypes of them all. -} - -{ % Scope for N_min, M_min, N_firstMin. - -\def\Nall{\ensuremath{N_{\mbox{\scriptsize{}all}}}} -\def\Mall{\ensuremath{M_{\mbox{\scriptsize{}all}}}} -\def\MallFirst{\ensuremath{M_{\mbox{\scriptsize{}first}}}} - -\LMHash{}% -Otherwise, when a set $N$ as specified above exists, -let \Nall{} be the greatest set satisfying the requirement on $N$, -and let $\Mall{} = \{ m_i\;|\;i \in \Nall\}$. -\commentary{ -That is, \Mall{} contains all member signatures named \id{} -with the most specific type. -Dart subtyping is a partial pre-order, -which ensures that such a greatest set of least elements exists, -if any non-empty set of least elements exist. -We can have several such signatures because member signatures -can be such that they are not equal, -and yet their function types are subtypes of each other. -We need to compute one member signature from \Mall{}, -and we do that by using the ordering of the given interfaces. -} - -\LMHash{}% -Let $j \in 1 .. k$ be the smallest number such that -$\MallFirst{} = \Mall{} \cap I_j$ is non-empty. -Let $m_i$ be the single element that \MallFirst{} contains. -\commentary{ -This set contains exactly one element because it is non-empty -and no interface contains more than one member signature named \id. -In other words, we choose $m_i$ as the member signature from -the first possible interface -among the most specific member signatures \Mall. -} -} - -\LMHash{} -The combined member signature is then $m'$, -which is obtained from $m_i$ by adding the modifier \COVARIANT{} -to each parameter $p$ (if it is not already present) -when there exists a $j \in 1 .. q$ -such that the parameter corresponding to $p$ -(\ref{covariantParameters}) -has the modifier \COVARIANT{}. -\commentary{ -In other words, -each parameter in the combined member signature is marked covariant -if any of the corresponding parameters are marked covariant, -not just among the most specific signatures, -but among \emph{all} signatures named \id{} (which are accessible to $L$) -in the given list of interfaces.% -} -\EndCase - - -\subsection{Superinterfaces} -\LMLabel{interfaceSuperinterfaces} - -\LMHash{}% -An interface has a set of direct superinterfaces -(\ref{interfaces}). -An interface $J$ is a \Index{superinterface} of an interface $I$ -if{}f either $J$ is a direct superinterface of $I$ -or $J$ is a superinterface of a direct superinterface of $I$. - - -\subsubsection{Inheritance and Overriding} -\LMLabel{interfaceInheritanceAndOverriding} - -\LMHash{}% -Let $J$ be an interface and $K$ be a library. -We define $\inherited{J, K}$ to be the set of member signatures $m$ -such that all of the following hold: -\begin{itemize} -\item $m$ is accessible to $K$ and -\item $A$ is a direct superinterface of $J$ and either - \begin{itemize} - \item $A$ declares a member signature $m$ or - \item $m$ is a member of $\inherited{A, K}$. - \end{itemize} -\item $m$ is not overridden by $J$. -\end{itemize} - -\LMHash{}% -Furthermore, we define $\overrides{J, K}$ to be -the set of member signatures $m'$ -such that all of the following hold: -\begin{itemize} -\item $J$ is the interface of a class $C$. -\item $C$ declares a member signature $m$. -\item $m'$ has the same name as $m$. -\item $m'$ is accessible to $K$. -\item $A$ is a direct superinterface of $J$ and either - \begin{itemize} - \item $A$ declares a member signature $m'$ or - \item $m'$ is a member of $inherited(A, K)$. - \end{itemize} -\end{itemize} - -\LMHash{}% -Let $I$ be the interface of a class $C$ declared in library $L$. -$I$ \Index{inherits} all members of $\inherited{I, L}$ -and $I$ \Index{overrides} $m'$ if $m' \in \overrides{I, L}$. - -\LMHash{}% -All the compile-time errors pertaining to the overriding of instance members -given in section~\ref{classes} hold for overriding between interfaces as well. - -\LMHash{}% -If the above rule would cause multiple member signatures -with the same name \id{} to be inherited then -exactly one member is inherited, namely -the combined member signature named \id{}, -from the direct superinterfaces -% This is well-defined because $I$ is a class interface. -in the textual order that they are declared, -with respect to $L$ -(\ref{combinedMemberSignatures}). -It is a compile-time error -if the computation of said combined member signature fails. - - -\subsubsection{Correct Member Overrides} -\LMLabel{correctMemberOverrides} - -\LMHash{}% -Let $m$ and $m'$ be member signatures with the same name \id. -Then $m$ is a \Index{correct override} of $m'$ -if{}f the following criteria are all satisfied: - -\begin{itemize} -\item - $m$ and $m'$ are both methods, both getters, or both setters. - % We cannot have a setter and a method, say, because they cannot have - % the same name. However, we must _allow_ $m$ and $m'$ to be two setters. -\item - If $m$ and $m'$ are both methods or both setters: - Let $F$ be the function type of $m$ - except that the parameter type is the built-in class \code{Object} - for each parameter of $m$ which has the modifier \COVARIANT{}. - Let $F'$ be the function type of $m'$. - $F$ must then be a subtype of $F'$. - - \commentary{% - The subtype requirement ensures that argument list shapes - that are admissible for an invocation of a method with signature $m'$ - are also admissible for an invocation of a method with signature $m$. - For instance, $m'$ may accept 2 or 3 positional arguments, - and $m$ may accept 1, 2, 3, or 4 positional arguments, but not vice versa. - This is a built-in property of the function type subtype rules. - % - Note that a member signature differs from - an underlying syntactic declaration $D$ in a class $C$. - In particular, - a parameter in a member signature has the modifier \COVARIANT{} - if and only if the parameter is covariant-by-declaration - (\ref{covariantParameters}), - and that may be the case due to declarations in a supertype of $C$, - so that modifier need not be present in $D$. - % - There is an additional potential compile-time error associated with - a parameter which is covariant-by-declaration - (\ref{instanceMethods}). - But we cannot cover that here as a property of member overrides, - because it is concerned with declarations in all superinterfaces, - indirect as well as direct. - } -\item - If $m$ and $m'$ are both methods, - $p$ is an optional parameter of $m$, - $p'$ is the parameter of $m'$ corresponding to $p$, - $p$ has default value $d$ and $p'$ has default value $d'$, - then $d$ and $d'$ must be identical, - or a static warning occurs. -\item - If $m$ and $m'$ are both getters: - The return type of $m$ must be a subtype of the return type of $m'$. -\end{itemize} - - -\section{Mixins} -\LMLabel{mixins} - -\LMHash{}% -A mixin describes the difference between a class and its superclass. -A mixin is either derived from an existing class declaration -or introduced by a mixin declaration. - -\LMHash{}% -Mixin application occurs when one or more mixins are mixed into a class declaration via its \WITH{} clause (\ref{mixinApplication}). -Mixin application may be used to extend a class per section \ref{classes}; -alternatively, a class may be defined as a mixin application as described in the following section. - -\subsection{Mixin Classes} -\LMLabel{mixinClasses} - -\begin{grammar} - ::= \gnewline{} - ? `=' `;' - - ::= ? -\end{grammar} - -\LMHash{}% -It is a compile-time error if an element in the type list of the \WITH{} clause of a mixin application is -a type variable (\ref{generics}), -a function type (\ref{functionTypes}), -a type alias that does not denote a class (\ref{typedef}), -an enumerated type (\ref{enums}), -a deferred type (\ref{staticTypes}), -type \DYNAMIC{} (\ref{typeDynamic}), -type \VOID{} (\ref{typeVoid}), -or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). -If $T$ is a type in a \WITH{} clause, \IndexCustom{the mixin of}{type!mixin of} -$T$ is either the mixin derived from $T$ if $T$ denotes a class, -or the mixin introduced by $T$ if $T$ denotes a mixin declaration. - -\LMHash{}% -Let $D$ be a mixin application class declaration of the form -\begin{normativeDartCode} -\ABSTRACT? \CLASS{} $N$ = $S$ \WITH{} $M_1$, \ldots{}, $M_n$ \IMPLEMENTS{} $I_1$, \ldots, $I_k$; -\end{normativeDartCode} - -\LMHash{}% -It is a compile-time error if $S$ is an enumerated type (\ref{enums}). -It is a compile-time error if any of $M_1, \ldots, M_k$ is an enumerated type (\ref{enums}). -It is a compile-time error if a well formed mixin cannot be derived from each of $M_1, \ldots, M_k$. - -\LMHash{}% -The effect of $D$ in library $L$ is to introduce the name $N$ into the scope of $L$, bound to the class (\ref{classes}) defined by the clause \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$} with name $N$, as described below. -If $k > 0$ then the class also implements $I_1$, \ldots{}, $I_k$. -If{}f the class declaration is prefixed by the built-in identifier \ABSTRACT{}, the class being defined is made an abstract class. - -\LMHash{}% -A clause of the form \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$} -with name $N$ defines a class as follows: - -\LMHash{}% -If there is only one mixin ($n = 1$), then \code{$S$ \WITH{} $M_1$} -defines the class yielded by the mixin application (\ref{mixinApplication}) -of the mixin of $M_1$ (\ref{mixinDeclaration}) to the class denoted by -$S$ with name $N$. - -\LMHash{}% -If there is more than one mixin ($n > 1$), then -let $X$ be the class defined by \code{$S$ \WITH{} $M_1$, \ldots{}, $M_{n-1}$} -with name $F$, where $F$ is a fresh name, and make $X$ abstract. -Then \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$} defines the class yielded -by the mixin application of the mixin of $M_n$ to the class $X$ with name $N$. - -\LMHash{}% -In either case, let $K$ be a class declaration with the same constructors, superclass, interfaces and instance members as the defined class. -It is a compile-time error if the declaration of $K$ would cause a compile-time error. -% TODO(eernst): Not completely! -% We do not want super-invocations on covariant implementations -% to be compile-time errors. - -\commentary{ -It is an error, for example, if $M$ contains a member declaration $d$ which overrides a member signature $m$ in the interface of $S$, but which is not a correct override of $m$ (\ref{correctMemberOverrides}). -} - -\subsection{Mixin Declaration} -\LMLabel{mixinDeclaration} - -\LMHash{}% -A mixin defines zero or more \IndexCustom{mixin member declarations}{mixin!member declaration}, -zero or more \IndexCustom{required superinterfaces}{mixin!required superinterface}, -one \IndexCustom{combined superinterface}{mixin!combined superinterface}, -and zero or more \IndexCustom{implemented interfaces}{mixin!implemented interface}. - -\LMHash{}% -The mixin derived from a class declaration: -\begin{normativeDartCode} -\ABSTRACT? \CLASS{} $X$ \IMPLEMENTS{} $I_1$, \ldots{}, $I_k$ \{ - \metavar{members} -\} -\end{normativeDartCode} -has \code{Object} as required superinterface -and combined superinterface, -$I_1$, \ldots, $I_k$ as implemented interfaces, -and the instance members of \metavar{members} as mixin member declarations. -If $X$ is generic, so is the mixin. - -\LMHash{}% -A mixin declaration introduces a mixin and provides a scope -for static member declarations. - -\begin{grammar} - ::= \MIXIN{} ? - \gnewline{} (\ON{} )? ? - \gnewline{} `\{' ( )* `\}' -\end{grammar} - -\LMHash{} -It is a compile-time error to declare a constructor in a mixin-declaration. - -\LMHash{} -A mixin declaration with no \code{\ON{}} clause is equivalent -to one with the clause \code{\ON{} Object}. - -\LMHash{} -Let $M$ be a \MIXIN{} declaration of the form -\begin{normativeDartCode} -\MIXIN{} $N$<\TypeParametersStd> \ON{} \List{T}{1}{n} \IMPLEMENTS{} \List{I}{1}{k} \{ - \metavar{members} -\} -\end{normativeDartCode} -It is a compile-time error if any of the types $T_1$ through $T_n$ -or $I_1$ through $I_k$ is -a type variable (\ref{generics}), -a function type (\ref{functionTypes}), -a type alias not denoting a class (\ref{typedef}), -an enumerated type (\ref{enums}), -a deferred type (\ref{staticTypes}), -type \DYNAMIC{} (\ref{typeDynamic}), -type \VOID{} (\ref{typeVoid}), -or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). - -\LMHash{}% -Let $M_S$ be the interface declared by the class declaration -\begin{normativeDartCode} -abstract \CLASS{} $M_{super}$<$P_1$, \ldots{}, $P_m$> implements $T_1$, $\dots{}$, $T_n$ \{\} -\end{normativeDartCode} -where $M_{super}$ is a fresh name. -It is a compile-time error for the mixin declaration if the $M_S$ -class declaration would cause a compile-time error, -\commentary{ -that is, if any member is declared by more than one declared superinterface, -and there is not a most specific signature for that member among the super -interfaces}. -The interface $M_S$ is called the -\Index{superinvocation interface} of the mixin declaration $M$. -\commentary{ -If the mixin declaration $M$ has only one declared superinterface, $T_1$, -then the superinvocation interface $M_{super}$ has exactly the same members -as the interface $T_1$.} - -\LMHash{} -Let $M_I$ be the interface that would be defined by the class declaration -\begin{normativeDartCode} -\ABSTRACT{} \CLASS{} $N$<\TypeParametersStd> \IMPLEMENTS{} \List{T}{1}{n}, \List{I}{1}{k} \{ - $\metavar{members}'$ -\} -\end{normativeDartCode} -where $\metavar{members}'$ are the member declarations of -the mixin declaration $M$ except that all superinvocations are treated -as if \SUPER{} was a valid expression with static type $M_S$. -It is a compile-time error for the mixin $M$ if this $N$ class -declaration would cause a compile-time error, \commentary{that is, if the -required superinterfaces, the implemented interfaces and the declarations do not -define a consistent interface, if any member declaration contains a -compile-time error other than a super-invocation, or if a super-invocation -is not valid against the interface $M_S$}. -The interface introduced by the mixin declaration $M$ has the same member -signatures and superinterfaces as $M_I$. - -\LMHash{}% -The mixin declaration $M$ introduces a mixin -with the \NoIndex{required superinterface}s $T_1$, \ldots{}, $T_n$, -the \NoIndex{combined superinterface} $M_S$, -\NoIndex{implemented interface}s $I_1$, \ldots{}, $I_k$ -and the instance members declared in $M$ as \Index{mixin member declarations}. - -\subsection{Mixin Application} -\LMLabel{mixinApplication} - -\LMHash{}% -A mixin may be applied to a superclass, yielding a new class. - -\LMHash{}% -Let $S$ be a class, -$M$ be a mixin with \NoIndex{required superinterface}s $T_1$, \ldots, $T_n$, -\NoIndex{combined superinterface} $M_S$, -\NoIndex{implemented interfaces} $I_1$, \ldots{}, $I_k$ and -\metavar{members} as \NoIndex{mixin member declarations}, -and let $N$ be a name. - -\LMHash{}% -It is a compile-time error to apply $M$ to $S$ if $S$ does not implement, -directly or indirectly, all of $T_1$, \ldots, $T_n$. -It is a compile-time error if any of \metavar{members} contains a -super-invocation of a member $m$ \commentary{(for example \code{super.foo}, -\code{super + 2}, or \code{super[1] = 2})}, and $S$ does not have a concrete -implementation of $m$ which is a valid override of the member $m$ in -the interface $M_S$. \rationale{We treat super-invocations in mixins as -interface invocations on the combined superinterface, so we require the -superclass of a mixin application to have valid implementations of those -interface members that are actually super-invoked.} - -\LMHash{}% -The mixin application of $M$ to $S$ with name $N$ introduces a new -class, $C$, with name $N$, superclass $S$, -implemented interface $I_1$, \ldots{}, $I_k$ -and \metavar{members} as instance members. -The class $C$ has no static members. -If $S$ declares any generative constructors, then the application -introduces generative constructors on $C$ as follows: - -\LMHash{}% -Let $L_C$ be the library containing the mixin application. -\commentary{That is, the library containing the clause \code{$S$ \WITH{} $M$} -or the clause \code{$S_0$ \WITH{} $M_1$, \ldots,\ $M_k$, $M$} giving rise -to the mixin application.} - -Let $S_N$ be the name of $S$. - -For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, $\ldots$, $T_{k}$ $a_{k}$)} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form - -\begin{normativeDartCode} -$C_q$($T_{1}$ $a_{1}$, \ldots, $T_{k}$ $a_{k}$): $\SUPER_q$($a_{1}$, $\ldots$, $a_{k}$); -\end{normativeDartCode} - -\noindent -where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$, -which denote the superclass, by $N$, and $\SUPER_q$ is obtained from $S_q$ by -replacing occurrences of $S_N$ which denote the superclass by \SUPER{}. -If $S_q$ is a generative const constructor, and $C$ does not declare any -instance variables, $C_q$ is also a const constructor. - -\LMHash{}% -For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d_p$])} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form - -\begin{normativeDartCode} -$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d'_{1}$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d'_p$]) - : $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$, \ldots, $a_p$); -\end{normativeDartCode} - -\noindent -where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$, -which denote the superclass, by $N$, -$\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$ -which denote the superclass by \SUPER{}, -and $d'_i$, $i \in 1..p$, is a constant expression evaluating -to the same value as $d_i$. -If $S_q$ is a generative const constructor, and $MC$ does not declare any -instance variables, $C_q$ is also a const constructor. - -\LMHash{}% -For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d_n$\})} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form - -\begin{normativeDartCode} -$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d'_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d'_n$\}) - : $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$: $a_{k+1}$, \ldots, $a_p$: $a_p$); -\end{normativeDartCode} - -\noindent -where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$ -which denote the superclass by $N$, -$\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$ -which denote the superclass by \SUPER{}, -and $d'_i$, $i \in 1..n$, is a constant expression evaluating to the same value as $d_i$. -If $S_q$ is a generative const constructor, and $M$ does not declare any -fields, $C_q$ is also a const constructor. - - -\section{Enums} -\LMLabel{enums} - -\LMHash{}% -An \Index{enumerated type}, or \Index{enum}, is used to represent a fixed number of constant values. - -\begin{grammar} - ::= \ENUM{} - \gnewline{} `{' (`,' )* (`,')? `}' - - ::= -\end{grammar} - -\LMHash{}% -The declaration of an enum of the form -\code{$m$ \ENUM{} $E$ \{$m_0\,\,\id_0, \ldots,\ m_{n-1}\,\,\id_{n-1}$\}} -has the same effect as a class declaration - -\begin{normativeDartCode} -$m$ \CLASS{} $E$ \{ -\ \ \FINAL{} int index; -\ \ \CONST{} $E$(\THIS{}.index); -\ \ $m_0$ \STATIC{} \CONST{} $E$ $\id_0$ = \CONST{} $E$(0); -\ \ $\ldots$ -\ \ $m_{n-1}$ \STATIC{} \CONST{} $E$ $\id_{n-1}$ = const $E$(n - 1); -\ \ \STATIC{} \CONST{} List<$E$> values = const <$E$>[\id$_0, \ldots, $ \id$_{n-1}$]; -\ \ String toString() => \{ 0: `$E$.\id$_0$', $\ldots$, n-1: `$E$.\id$_{n-1}$'\}[index] -\} -\end{normativeDartCode} - -\commentary{ -It is also a compile-time error to subclass, mix-in or implement an enum or to explicitly instantiate an enum. -These restrictions are given in normative form in sections \ref{superclasses}, \ref{superinterfaces}, \ref{mixinApplication} and \ref{instanceCreation} as appropriate. -} - - -\section{Generics} -\LMLabel{generics} - -\LMHash{}% -A class declaration (\ref{classes}), type alias (\ref{typedef}), or function (\ref{functions}) $G$ may be \Index{generic}, that is, $G$ may have formal type parameters declared. - -\LMHash{}% -When an entity in this specification is described as generic, -and the special case is considered where the number of type arguments is zero, -the type argument list should be omitted. - -\commentary{ -This allows non-generic cases to be included implicitly as special cases. -For example, -an invocation of a non-generic function arises as the special case -where the function takes zero type arguments, -and zero type arguments are passed. -In this situation some operations are also omitted (have no effect), e.g., -operations where formal type parameters are replaced by actual type arguments. -} - -\LMHash{}% -A \IndexCustom{generic class declaration}{class declaration!generic} -introduces a generic class into the enclosing library scope. -A \IndexCustom{generic class}{class!generic} -is a mapping that accepts a list of actual type arguments and maps them to a class. -Consider a generic class declaration $G$ named $C$ with formal type parameter declarations -$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$, -and a parameterized type $T$ of the form \code{$C$<$T_1, \ldots,\ T_l$>}. - -\LMHash{}% -It is a compile-time error if $m \not= l$. -It is a compile-time error if $T$ is not well-bounded -(\ref{superBoundedTypes}). - -\LMHash{}% -Otherwise, said parameterized type \code{$C$<$T_1, \ldots,\ T_m$>} denotes an application of the generic class declared by $G$ to the type arguments $T_1, \ldots, T_m$. -This yields a class $C'$ whose members are equivalent to those of a class declaration which is obtained from the declaration $G$ by replacing each occurrence of $X_j$ by $T_j$. -\commentary{ - -% TODO(eernst): make sure this list of properties is complete. -Other properties of $C'$ such as the subtype relationships are specified elsewhere -(\ref{subtypes}). -} - -\LMHash{}% -A \IndexCustom{generic type alias}{type alias!generic} -is a declaration $D$ of one of the following forms: - -\begin{itemize} -\item \code{$m$ \TYPEDEF{} \id<\TypeParametersStd> = $T$;} -\item \code{$m$ \TYPEDEF{} $S$?\ \id<\TypeParametersStd>(\\ - \mbox\quad\PairList{T}{p}{1}{n},\ [\PairList{T}{p}{n+1}{n+k}]);} -\item \code{$m$ \TYPEDEF{} $S$?\ \id<\TypeParametersStd>(\\ - \mbox\quad\PairList{T}{p}{1}{n},\ \{\PairList{T}{p}{n+1}{n+k}\});} -\end{itemize} - -\noindent -where $m$ is derived from \synt{metadata}, -$T$ is a type, -and \code{$S$?} is a type or the empty string. -Let $S'$ be \code{$S$?} if it is a type, otherwise let $S'$ be \DYNAMIC. -The associated type of $D$, call it $F$, is, respectively: - -\begin{itemize} -\item $T$ -\item \FunctionTypeSimple{S'}{\FunctionTypePositionalArgumentsStd} -\item \FunctionTypeSimple{S'}{\FunctionTypeNamedArgumentsStd} -\end{itemize} - -\LMHash{}% -$D$ introduces a mapping from actual type argument lists to types. -Under the assumption that \List{X}{1}{s} are types such that -$X_j <: B_j$, for all $j \in 1 .. s$, -it is a compile-time error if $T$ is not regular-bounded, -and it is a compile-time error if any type occurring in $T$ is not well-bounded. - -\commentary{ -This means that the bounds declared for -the formal type parameters of a generic type alias -must be such that when they are satisfied, -the bounds that pertain to the body are also satisfied, -and a type occurring as a subterm of the body can violate its bounds, -but only if it is a correct super-bounded type. -} - -\LMHash{}% -Moreover, -let $T_1,\ \ldots,\ T_l$ be types -and let $U$ be the parameterized type \code{\id<$T_1, \ldots,\ T_l$>} -in a location where \id{} denotes $D$. -It is a compile-time error if $l \not= s$. -It is a compile-time error if $U$ is not well-bounded -(\ref{superBoundedTypes}). - -\LMHash{}% -Otherwise, -$U$ denotes an application of the mapping denoted by $D$ to the type arguments -$T_1, \ldots, T_s$, -yielding the type -$[T_1/X_1, \ldots, T_s/X_s]F$. - -\commentary{% -Note that the type alias syntax without \lit{=} -can only express function types, -and it cannot express the type of a generic function. -When such a type alias is generic, -it always expresses a family of non-generic function types. -These restrictions exist because that syntax was defined -before generic functions were added to Dart.% -} - -\rationale{ -The requirement that satisfaction of the bounds on -the formal type parameters of a generic type alias $D$ -must imply satisfaction of all bounds pertaining to -every type that occurs in the body of $D$ -limits the expressive power of generic type aliases. -However, it would require the constraints on formal type parameters -to be expressed in a much more powerful language -if we were to allow a significantly larger set of types -to be expressed using a generic type alias. -} - -\commentary{ -For example, consider the following code: -} - -\begin{dartCode} -\CLASS{} A \{\} -\TYPEDEF{} F = A<\VOID{} \FUNCTION(Y)> \FUNCTION(); // \comment{compile-time error} -\end{dartCode} - -\commentary{ -There is no way to specify a bound on \code{Y} in the declaration of \code{F} -which will ensure that all bounds on the right hand side are respected. -This is because the actual requirement is that \code{Y} must be -a \emph{supertype} of \code{num}, -but Dart does not support lower bounds for type parameters. -The type \code{A<\VOID{} \FUNCTION(U)> \FUNCTION()} -can still be specified explicitly -for every \code{U} which satisfies the bounds declared by \code{A}. -So the types can be expressed, -they just cannot be abbreviated using a generic type alias. -} - -\LMHash{}% -A \IndexCustom{generic type}{type!generic} is a type which is introduced by -a generic class declaration or a generic type alias, -or it is the type \code{FutureOr}. - -\LMHash{}% -A \IndexCustom{generic function declaration}{function declaration!generic} -introduces a generic function (\ref{formalParameters}) into the enclosing scope. -Consider a function invocation expression of the form -\code{f<$T_1, \ldots,\ T_l$>(\ldots)}, -where the static type of \code{f} is a generic function type with formal type parameters -$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$. - -\LMHash{}% -It is a compile-time error if $m \not= l$. -It is a compile-time error if there exists a $j$ -such that $T_j$ is not a subtype of $[T_1/X_1, \ldots, T_m/X_m]B_j$. - -\commentary{ -That is, if the number of type arguments is wrong, -or if the $j$th actual type argument is not a subtype of the corresponding bound, -where each formal type parameter has been replaced by the corresponding actual type argument. -} - -\begin{grammar} - ::= (\EXTENDS{} )? - - ::= `<' (`,' )* `>' -\end{grammar} - -\LMHash{}% -A type parameter $T$ may be suffixed with an \EXTENDS{} clause that specifies the \Index{upper bound} for $T$. -If no \EXTENDS{} clause is present, the upper bound is \code{Object}. -It is a compile-time error if a type parameter is a supertype of its upper bound -when that upper bound is itself a type variable. - -\commentary{ -This prevents circular declarations like -\code{X \EXTENDS{} X} -and -\code{X \EXTENDS{} Y, Y \EXTENDS{} X}. -} - -\LMHash{}% -Type parameters are declared in the type parameter scope of a class or function. -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$. - -\commentary{% -However, a type parameter of a generic class -is considered to be a malformed type -when referenced by a static member -(\ref{staticTypes}). -The scopes associated with the type parameters of a generic function are described in (\ref{formalParameters}). -} - -\rationale{ -The restriction on static members is necessary since a type variable has no meaning in the context of a static member, -because statics are shared among all generic instantiations of a generic class. -However, a type variable may be referenced from an instance initializer, -even though \THIS{} is not available. -} - -\commentary{ -Because type parameters are in scope in their bounds, we support F-bounded quantification (if you don't know what that is, don't ask). -This enables typechecking code such as: -} - -\begin{dartCode} -\CLASS{} Ordered \{ - operator >(T x); -\} - -\CLASS{} Sorter l) {... l[n] < l[n+1] ...} -\} - -\end{dartCode} - -\commentary{ -Even where type parameters are in scope there are numerous restrictions at this time: -\begin{itemize} -\item[$\bullet$] A type parameter cannot be used to name a constructor in an instance creation expression (\ref{instanceCreation}). -\item[$\bullet$] A type parameter cannot be used as a superclass or superinterface (\ref{superclasses}, \ref{superinterfaces}, \ref{interfaceSuperinterfaces}). -\item[$\bullet$] A type parameter cannot be used as a generic type. -\end{itemize} - -The normative versions of these are given in the appropriate sections of this specification. -Some of these restrictions may be lifted in the future. -} - -%The {\em induced type set}, $S$, of a parameterized type $T$ is the set consisting of -%\begin{itemize} -%\item The supertypes of any type in $S$. -%\item The type arguments of any parameterized type in $S$. -%\end{itemize} - -%Let $P$ be the generic instantiation of a generic type with its own type parameters. It is a compile-time error if the induced type set of $P$ is not finite. - -%\rationale {A typical recursive type declaration such as} - -%\begin{dartCode} -%\CLASS{} B \{\} -%\CLASS{} D \EXTENDS{} B>$ \{\} -%\end{dartCode} - -%\rationale{ -%poses no problem under this rule. The generic instantiation \code{D} has an induced -%set consisting of: \code{B>$, Object, D, T}. However, the following variant -%} - -%\begin{dartCode} -%\CLASS{} B \{\} -%\CLASS{} D \EXTENDS{} B>>$ \{\} -%\end{dartCode} - -%\rationale{ -%is disallowed. Consider again the generic instantiation \code{D}. It leads to the -%superclass \code{B>>$}, and so adds \code{D>$} to the induced set. The latter in turn leads to \code{B>>>$} and \code{D>>$} -%and so on ad infinitum.} - -%\commentary{ -%The above requirement does not preclude the use of arbitrary recursive types in the body of a generic class. } -%A generic has a type parameter scope. The enclosing scope of a type parameter scope of a generic G is the enclosing scope of G. - -%class T {...} - -%class G extends T; - -%By current rules, this is illegal. Make sure we preserve this. - - -\subsection{Variance} -\LMLabel{variance} - -\LMHash{}% -We say that a type $S$ \Index{occurs covariantly} in a type $T$ if{}f -$S$ occurs in a covariant position in $T$, -but not in a contravariant position, -and not in an invariant position. - -\LMHash{}% -We say that a type $S$ \Index{occurs contravariantly} in a type $T$ if{}f -$S$ occurs in a contravariant position in $T$, -but not in a covariant position, -and not in an invariant position. - -\LMHash{}% -We say that a type $S$ \Index{occurs invariantly} in a type $T$ if{}f -$S$ occurs in an invariant position in $T$, -or $S$ occurs in a covariant position as well as a contravariant position. - -\LMHash{}% -We say that a type $S$ occurs in a \Index{covariant position} in a type $T$ -if{}f one of the following conditions is true: - -\begin{itemize} -\item $T$ is $S$ - -\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>} - where $G$ denotes a generic class - and $S$ occurs in a covariant position in $S_j$ for some $j \in 1 .. n$. - -\item $T$ is of the form - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>($S_1\ x_1, \ldots$)} - where the type parameter list may be omitted, - and $S$ occurs in a covariant position in $S_0$. - -\item $T$ is of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])} - - \noindent - or of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})} - - \noindent - where the type parameter list and each default value may be omitted, - and $S$ occurs in a contravariant position in $S_j$ - for some $j \in 1 .. n$. - -\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>} - where $G$ denotes a generic type alias such that - $j \in 1 .. n$, - the formal type parameter corresponding to $S_j$ is covariant, - and $S$ occurs in a covariant position in $S_j$. - -\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>} - where $G$ denotes a generic type alias such that - $j \in 1 .. n$, - the formal type parameter corresponding to $S_j$ is contravariant, - and $S$ occurs in a contravariant position in $S_j$. -\end{itemize} - -\LMHash{}% -We say that a type $S$ occurs in a \Index{contravariant position} in a type $T$ -if{}f one of the following conditions is true: - -\begin{itemize} -\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>} - where $G$ denotes a generic class - and $S$ occurs in a contravariant position in $S_j$ - for some $j \in 1 .. n$. - -\item $T$ is of the form - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>($S_1\ x_1, \ldots$)} - where the type parameter list may be omitted, - and $S$ occurs in a contravariant position in $S_0$. - -\item $T$ is of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])} - - \noindent - or of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})} - - \noindent - where the type parameter list and each default value may be omitted, - and $S$ occurs in a covariant position in $S_j$ - for some $j \in 1 .. n$. - -\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>} - where $G$ denotes a generic type alias such that - $j \in 1 .. n$, - the formal type parameter corresponding to $S_j$ is covariant, - and $S$ occurs in a contravariant position in $S_j$. - -\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>} - where $G$ denotes a generic type alias such that - $j \in 1 .. n$, - the formal type parameter corresponding to $S_j$ is contravariant, - and $S$ occurs in a covariant position in $S_j$. -\end{itemize} - -\LMHash{}% -We say that a type $S$ occurs in an \Index{invariant position} in a type $T$ -if{}f one of the following conditions is true: - -\begin{itemize} -\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>} - where $G$ denotes a generic class or a generic type alias, - and $S$ occurs in an invariant position in $S_j$ for some $j \in 1 .. n$. - -\item $T$ is of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])} - - \noindent - or of the form - - \code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>} - - \code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k, - $ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})} - - \noindent - where the type parameter list and each default value may be omitted, - and $S$ occurs in an invariant position in $S_j$ - for some $j \in 0 .. n$, - or $S$ occurs in $B_i$ - for some $i \in 1 .. m$. - -\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>} - where $G$ denotes a generic type alias, - $j \in 1 .. n$, - the formal type parameter corresponding to $S_j$ is invariant, - and $S$ occurs in $S_j$. -\end{itemize} - -\LMHash{}% -Consider a generic type alias declaration $G$ -with formal type parameter declarations -$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$, -and right hand side $T$. -Let $j \in 1 .. m$. -% -We say that -\IndexCustom{the formal type parameter $X_j$ is invariant}{% - type parameter!invariant} -if{}f $X_j$ occurs invariantly in $T$, $X_j$ -\IndexCustom{is covariant}{type parameter!covariant} -if{}f $X_j$ occurs covariantly in $T$, and $X_j$ -\IndexCustom{is contravariant}{type parameter!contravariant} -if{}f $X_j$ occurs contravariantly in $T$. - -\rationale{ -Variance gives a characterization of the way a type varies -as the value of a subterm varies, e.g., a type variable: -Assume that $T$ is a type where a type variable $X$ occurs, -and $L$ and $U$ are types such that $L$ is a subtype of $U$. -If $X$ occurs covariantly in $T$ -then $[L/X]T$ is a subtype of $[U/X]T$. -Similarly, if $X$ occurs contravariantly in $T$ -then $[U/X]T$ is a subtype of $[L/X]T$. -If $X$ occurs invariantly -then $[L/X]T$ and $[U/X]T$ are not guaranteed to be subtypes of each other in any direction. -In short: with covariance, the type covaries; -with contravariance, the type contravaries; -with invariance, all bets are off. -} - - -\subsection{Super-Bounded Types} -\LMLabel{superBoundedTypes} - -\LMHash{}% -This section describes how -the declared upper bounds of formal type parameters are enforced, -including some cases where a limited form of violation is allowed. - -\LMHash{}% -A \Index{top type} is a type $T$ such that \code{Object} is a subtype of $T$. -\commentary{ -For instance, \code{Object}, \DYNAMIC, and \VOID{} are top types, -and so are \code{FutureOr<\VOID>} and \code{FutureOr{}>}. -} - -% We define the property of being regular-bounded for all types, -% being super-bounded for parameterized types, and being well-bounded -% for all types. We require that all types are well-bounded, which -% covers every subterm of a type that is itself a type, and then we -% require that types must be regular-bounded when used in certain -% situations. - -\LMHash{}% -Every type which is not a parameterized type is \Index{regular-bounded}. - -\commentary{ -In particular, every non-generic class and every function type -is a regular-bounded type. -} - -\LMHash{}% -Let $T$ be a parameterized type of the form -\code{$G$<$S_1, \ldots,\ S_n$>} -where $G$ denotes a generic class or a generic type alias. -Let -\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_n\ \EXTENDS\ B_n$} -be the formal type parameter declarations of $G$. -$T$ is \Index{regular-bounded} if{}f -$S_j$ is a subtype of -$[S_1/X_1, \ldots,\ S_n/X_n]B_j$, -for all $j \in 1 .. n$. - -\commentary{ -This means that regular-bounded types are those types -that do not violate their type parameter bounds. -} - -\LMHash{}% -Let $T$ be a parameterized type of the form -\code{$G$<$S_1, \ldots,\ S_n$>} -where $G$ denotes a generic class or a generic type alias. -$T$ is \Index{super-bounded} if{}f the following conditions are both true: - -\begin{itemize} -\item - $T$ is not regular-bounded. -\item - Let $T'$ be the result of replacing every occurrence in $T$ - of a top type in a covariant position by \code{Null}, - and every occurrence in $T$ - of \code{Null} in a contravariant position by \code{Object}. - It is then required that $T'$ is regular-bounded. - % - Moreover, if $G$ denotes a generic type alias with body $U$, - it is required that every type that occurs as a subterm of - $[S_1/X_1, \ldots,\ S_n/X_n]U$ - is well-bounded (defined below). -\end{itemize} - -\commentary{ -In short, at least one type argument violates its bound, but the type is -regular-bounded after replacing all occurrences of an extreme type by an -opposite extreme type, depending on their variance. -} - -\LMHash{}% -A type $T$ is \Index{well-bounded} if{}f -it is either regular-bounded or super-bounded. - -\LMHash{}% -Any use of a type $T$ which is not well-bounded is a compile-time error. - -\LMHash{}% -It is a compile-time error if a parameterized type $T$ is super-bounded -when it is used in any of the following ways: -\begin{itemize} -\item $T$ is an immediate subterm of a new expression - (\ref{new}) - or a constant object expression - (\ref{const}). -\item $T$ is an immediate subterm of a redirecting factory constructor - signature - (\ref{redirectingFactoryConstructors}). -\item $T$ is an immediate subterm of an \EXTENDS{} clause of a class - (\ref{superclasses}), - or it occurs as an element in the type list of an \IMPLEMENTS{} clause - (\ref{superinterfaces}), - or a \WITH{} clause - (\ref{classes}). -\end{itemize} - -\commentary{ -It is \emph{not} an error if a super-bounded type occurs -as an immediate subterm of an \EXTENDS{} clause -that specifies the bound of a type variable -(\ref{generics}). -} - -\commentary{ -Types of members from super-bounded class types are computed using the same -rules as types of members from other types. Types of function applications -involving super-bounded types are computed using the same rules as types of -function applications involving other types. Here is an example: -} - -\begin{dartCode} -\CLASS{} A \{ - X x; -\} -\\ -A a; -\end{dartCode} - -\commentary{ -With this, \code{a.x} has static type \code{Object}, -even though the upper bound on the type variable \code{X} is \code{num}. -} - -\rationale{ -Super-bounded types enable the expression of informative common supertypes -of some sets of types whose common supertypes would otherwise be much less informative. -} - -\commentary{ -For example, consider the following class: -} - -\begin{dartCode} -\CLASS{} C$\!$> \{ - X next; -\} -\end{dartCode} - -\commentary{ -Without super-bounded types, -there is no type $T$ which makes \code{C<$T$>} a common supertype of -all types of the form \code{C<$S$>} -(noting that all types must be regular-bounded -when we do not have the notion of super-bounded types). -So if we wish to allow a variable to hold any instance ``of type \code{C}'' -then that variable must use \code{Object} or another top type -as its type annotation, -which means that a member like \code{next} is not known to exist -(which is what we mean by saying that the type is `less informative'). -} - -\rationale{ -We could introduce a notion of recursive (infinite) types, and express -the least upper bound of all types of the form \code{C<$S$>} as -some syntax whose meaning could be approximated by -\code{C$\!$>$\!$>$\!$>}. -% -However, we expect that any such concept in Dart would incur a significant cost -on developers and implementations in terms of added complexity and subtlety, -so we have chosen not to do that. -Super-bounded types are finite, -but they offer a useful developer-controlled approximation to such infinite types. -} - -\commentary{ -For example, -\code{C} and -\code{C{}>{}>} -are types that a developer may choose to use as a type annotation. -This choice serves as a commitment to -a finite level of unfolding of the infinite type, -and it allows for a certain amount of control -at the point where the unfolding ends: -% -If \code{c} has type \code{C{}>} -then \code{c.next.next} has type \DYNAMIC{} -and \code{c.next.next.whatever} has no compile-time error, -but if \code{c} has type \code{C{}>} then already -\code{Object x = c.next.next;} is a compile-time error. -It is thus possible for developers to get a more or less strict treatment -of expressions whose type proceeds beyond the given finite unfolding. -} - - -\subsection{Instantiation to Bound} -\LMLabel{instantiationToBound} - -\LMHash{}% -This section describes how to compute type arguments -that are omitted from a type, -or from an invocation of a generic function. - -\commentary{% -%% TODO(eernst): When we add a specification of type inference, we will adjust -%% the specification of i2b such that it allows for taking initial values for -%% the actual type arguments (that is, $U_{j,0}$ is given "from the caller" for -%% some $j$; probably "the caller" will always be type inference), and all other -%% parts of the algorithm remain unchanged. -%% I think it will be more confusing than helpful to start writing this now, -%% and it will be a small adjustment when we add a spec of type inference. So -%% at this point we just specify i2b as a stand-alone algorithm. -Note that type inference is assumed to have taken place already -(\ref{overview}), -so type arguments are not considered to be omitted if they are inferred. -This means that instantiation to bound is a backup mechanism, -which will be used when no information is available for inference.% -} - -\LMHash{}% -Consider the situation where a term $t$ of the form \synt{qualified} -(\commentary{which is syntactically the same as \synt{typeName}}) -denotes a generic type declaration, -and it is used as a type or as an expression in the enclosing program. -\commentary{% -This implies that type arguments are accepted, but not provided.% -} -We use the phrase -\Index{raw type} respectively \Index{raw type expression} -to identify such terms. -In the following we only mention raw types, -but everything said about raw types -applies to raw type expressions in the obvious manner. - -\commentary{% -For instance, with the declaration \code{Type listType() => List;}, -evaluation of the raw type expression \code{List} in the body yields -an instance of class \code{Type} reifying \code{List}, -because \code{List} is subject to instantiation to bound. -Note that \code{List} is not syntactically an expression, -but it is still possible to get access to -a \code{Type} instance reifying \code{List} -without instantiation to bound, -because it can be the value of a type variable.% -} - -\rationale{% -We can unambiguously define raw types to denote -the result of applying the generic type -to a list of implicitly provided actual type arguments, -and instantiation to bound is a mechanism which does just that. -This is because Dart does not, and will not, support higher-kinded types; -for example, the value of a type variable $X$ will be a type, -it cannot be the generic class \code{List} as such, -and it cannot be applied to type arguments, e.g., \code{$X$}.% -} - -\rationale{% -In the typical case where only covariance is encountered, -instantiation to bound will yield a \emph{supertype} of -all the regular-bounded types that can be expressed. -This allows developers to consider a raw type as a type -which is used to specify that -``the actual type arguments do not matter''$\!$.% -} -\commentary{% -For example, assuming the declaration -\code{\CLASS{} C \{\ldots\}}, -instantiation to bound on \code{C} yields \code{C}, -and this means that \code{C x;} can be used to declare a variable \code{x} -whose value can be a \code{C<$T$>} for \emph{all possible} values of $T$.% -} - -\rationale{% -Conversely, consider the situation where -a generic type alias denotes a function type, -and it has one type parameter which is contravariant. -Instantiation to bound on that type alias will then yield a \emph{subtype} of -all the regular-bounded types that can be expressed -by varying that type argument. -This allows developers to consider such a type alias used as a raw type -as a function type which allows the function to be passed to clients -``where it does not matter which values -for the type argument the client expects''$\!$.% -} -\commentary{% -E.g., with -\code{\TYPEDEF{} F = \FUNCTION(X);} -instantiation to bound on \code{F} yields \code{F}, -and this means that \code{F f;} can be used to declare a variable \code{f} -whose value will be a function that can be passed to clients expecting -an \code{F<$T$>} for \emph{all possible} values of $T$. -} - - -\subsubsection{Auxiliary Concepts for Instantiation to Bound} -\LMLabel{auxiliaryConceptsForInstantiationToBound} - -\LMHash{}% -Before we specify instantiation to bound we need to define two auxiliary concepts. -Let $T$ be a raw type. -A type $S$ then -\IndexCustom{raw-depends on}{raw-depends on!type} -$T$ if one or more of the following conditions hold: - -\begin{itemize} -\item - $S$ is of the form \synt{typeName}, and $S$ is $T$. - \commentary{% - Note that this case is not applicable - if $S$ is a subterm of a term of the form - \syntax{$S$ }, - that is, - if $S$ receives any type arguments. - Also note that $S$ cannot be a type variable, - because then `$S$ is $T$' cannot hold. - See the discussion below and the reference to~\ref{subtypeRules} - for more details about why this is so.% - } -\item - $S$ is of the form \syntax{ }, - and one of the type arguments raw-depends on $T$. -\item - $S$ is of the form \syntax{ ?}\ where - \synt{typeName} denotes a type alias $F$, - and the body of $F$ raw-depends on $T$. -\item - $S$ is of the form - \syntax{? \FUNCTION{} ? } and - \syntax{?}\ raw-depends on $T$, - or a bound in \syntax{?}\ raw-depends on $T$, - or a type in \synt{parameterTypeList} raw-depends on $T$. -\end{itemize} - -\commentary{% -Meta-variables -(\ref{metaVariables}) -like $S$ and $T$ are understood to denote types, -and they are considered to be equal (as in `$S$ is $T$') -in the same sense as in the section about subtype rules -(\ref{subtypeRules}). -% -In particular, -even though two identical pieces of syntax may denote two distinct types, -and two different pieces of syntax may denote the same type, -the property of interest here is whether they denote the same type -and not whether they are spelled identically. - -The intuition behind the situation where a type raw-depends on another type is -that we need to compute any missing type arguments for the latter -in order to be able to tell what the former means. - -In the rule about type aliases, $F$ may or may not be generic, -and type arguments may or may not be present. -However, there is no need to consider the result of substituting -actual type arguments for formal type parameters in the body of $F$ -(or even the correctness of passing those type arguments to $F$), -because we only need to inspect -all types of the form \synt{typeName} in its body, -and they are not affected by such a substitution. -In other words, raw-dependency is a relation -which is simple and cheap to compute. -} - -\LMHash{}% -Let $G$ be a generic class or a generic type alias -with $k$ formal type parameter declarations -containing formal type parameters \List{X}{1}{k} and bounds \List{B}{1}{k}. -For any $j \in 1 .. k$, -we say that the formal type parameter $X_j$ has a \Index{simple bound} -when one of the following requirements is satisfied: - -\begin{itemize} -\item $B_j$ is omitted. - -\item $B_j$ is included, but does not contain any of \List{X}{1}{k}. - If $B_j$ raw-depends on a raw type $T$ - then every type parameter of $T$ must have a simple bound. -\end{itemize} - -\LMHash{}% -The notion of a simple bound must be interpreted inductively rather than -coinductively, i.e., if a bound $B_j$ of a generic class or -generic type alias $G$ is reached during an investigation of whether -$B_j$ is a simple bound, the answer is no. - -\commentary{% -For example, with -\code{\CLASS{} C \{\}}, -the type parameter \code{X} does not have a simple bound: -A raw \code{C} is used as a bound for \code{X}, -so \code{C} must have simple bounds, -but one of the bounds of \code{C} is the bound of \code{X}, -and that bound is \code{C}, so \code{C} must have simple bounds: -That was a cycle, so the answer is ``no'', -\code{C} does not have simple bounds.% -} - -\LMHash{}% -Let $G$ be a generic class or a generic type alias. -We say that $G$ -\IndexCustom{has simple bounds}{type!generic, has simple bounds} -if{}f every type parameter of $G$ has simple bounds. - -\commentary{% -We can now specify in which sense instantiation to bound requires -the involved types to be "simple enough". -We impose the following constraint on all type parameter bounds, -because all type parameters may be subject to instantiation to bound.% -} - -\LMHash{}% -It is a compile-time error -if a formal type parameter bound $B$ contains a raw type $T$, -unless $T$ has simple bounds. - -\commentary{% -So type arguments on bounds can only be omitted -if they themselves have simple bounds. -In particular, -\code{\CLASS{} C \{\}} -is a compile-time error, -because the bound \code{C} is raw, -and the formal type parameter \code{X} -that corresponds to the omitted type argument -does not have a simple bound.% -} - -\LMHash{}% -Let $T$ be a type of the form \synt{typeName} -which denotes a generic class or a generic type alias -(\commentary{so $T$ is raw}). -Then $T$ is equivalent to the parameterized type which is -the result obtained by applying instantiation to bound to $T$. -It is a compile-time error if the instantiation to bound fails. - -\commentary{% -This rule is applicable for all occurrences of raw types, -e.g., when it occurs as a type annotation of a variable or a parameter, -as a return type of a function, -as a type which is tested in a type test, -as the type in an \synt{onPart}, -etc. -} - - -\subsubsection{The Instantiation to Bound Algorithm} -\LMLabel{theInstantiationToBoundAlgorithm} - -\LMHash{}% -We now specify how the -\Index{instantiation to bound} -algorithm proceeds. -Let $T$ be a raw type. -Let \List{X}{1}{k} be the formal type parameters in the declaration of $G$, -and let \List{B}{1}{k} be their bounds. -For each $i \in 1 .. k$, -let $S_i$ denote the result of instantiation to bound on $B_i$; -in the case where the $i$th bound is omitted, let $S_i$ be \DYNAMIC. - -\commentary{% -If $B_i$ for some $i$ is raw (in general: if it raw-depends on some type $U$) -then all its (respectively $U$'s) omitted type arguments have simple bounds. -This limits the complexity of instantiation to bound for $B_i$, -and in particular it cannot involve a dependency cycle -where we need the result from instantiation to bound for $G$ -in order to compute the instantiation to bound for $G$.% -} - -\LMHash{}% -Let $U_{i,0}$ be $S_i$, for all $i \in 1 .. k$. -\commentary{% -This is the "current value" of the bound for type variable $i$, at step 0; -in general we will consider the current step, $m$, and use data for that step, -e.g., the bound $U_{i,m}$, to compute the data for step $m + 1$.% -} - -{ %% Scope for definitions of relations used during i2b - -\def\Depends{\ensuremath{\rightarrow_m}} -\def\TransitivelyDepends{\ensuremath{\rightarrow^{+}_m}} - -\LMHash{}% -Let \Depends{} be a relation among the type variables -\List{X}{1}{k} such that -$X_p \Depends X_q$ iff $X_q$ occurs in $U_{p,m}$. -\commentary{% -So each type variable is related to, that is, depends on, -every type variable in its bound, which might include itself.% -} -Let \TransitivelyDepends{} be the transitive -(\commentary{but not reflexive}) -closure of \Depends. -For each $m$, let $U_{i,m+1}$, for $i \in 1 .. k$, -be determined by the following iterative process, where $V_m$ denotes -\code{$G$<$U_{1,m},\ \ldots,\ U_{k,m}$>}: - -\begin{itemize} -\item[1.] - If there exists a $j \in 1 .. k$ such that - $X_j \TransitivelyDepends X_j$ - (\commentary{that is, if the dependency graph has a cycle}) - let \List{M}{1}{p} be the strongly connected components (SCCs) - with respect to \Depends{}. - \commentary{ - That is, the maximal subsets of \List{X}{1}{k} - where every pair of variables in each subset - are related in both directions by \TransitivelyDepends; - note that the SCCs are pairwise disjoint; - also, they are uniquely defined up to reordering, - and the order does not matter for this algorithm.% - } - Let $M$ be the union of \List{M}{1}{p} - (\commentary{that is, all variables that participate in a dependency cycle}). - Let $i \in 1 .. k$. - If $X_i$ does not belong to $M$ then $U_{i,m+1}$ is $U_{i,m}$. - Otherwise there exists a $q$ such that $X_i \in M_q$; - $U_{i,m+1}$ is then obtained from $U_{i,m}$ - by substituting \DYNAMIC{} for every occurrence of a variable in $M_q$ - that is in a position in $V_m$ which is not contravariant, - and substituting \code{Null} for every occurrence of a variable in $M_q$ - which is in a contravariant position in $V_m$. - -\item[2.] - Otherwise (\commentary{when there are no dependency cycles}), - let $j$ be the lowest number such that $X_j$ occurs in $U_{p,m}$ for some $p$ - and $X_j \not\rightarrow_m X_q$ for all $q$ in $1 .. k$ - (\commentary{% - that is, the bound of $X_j$ does not contain any type variables, - but $X_j$ occurs in the bound of some other type variable% - }). - Then, for all $i \in 1 .. k$, - $U_{i,m+1}$ is obtained from $U_{i,m}$ - by substituting $U_{j,m}$ for every occurrence of $X_j$ - that is in a position in $V_m$ which is not contravariant, - and substituting \code{Null} for every occurrence of $X_j$ - which is in a contravariant position in $V_m$. - -\item[3.] - Otherwise (\commentary{when there are no dependencies at all}), - terminate with the result \code{<$U_{1,m},\ \ldots,\ U_{k,m}$>}. -\end{itemize} - -\commentary{% -This process will always terminate, because the total number of -occurrences of type variables from $\{\,\List{X}{1}{k}\,\}$ in -the current bounds is strictly decreasing with each step, and we terminate -when that number reaches zero. -} - -\rationale{% -It may seem somewhat arbitrary to treat unused and invariant parameters -in the same way as covariant parameters, -in particular because invariant parameters fail to satisfy the expectation that -a raw type denotes a supertype of all the expressible regular-bounded types. - -We could easily have made every instantiation to bound an error -when applied to a type where invariance occurs anywhere during the run of the algorithm. -However, there are a number of cases where this choice produces a usable type, -and we decided that it is not helpful to outlaw such cases.% -} - -\begin{dartCode} -\TYPEDEF{} Inv = X \FUNCTION(X); -\CLASS{} B{}> \{\} -\\ -B b; // \comment{The raw B means} B{}>. -\end{dartCode} - -\commentary{% -For example, the value of \code{b} can have dynamic type -\code{B}. -However, the type arguments have to be chosen carefully, -or the result will not be a subtype of \code{B}. -For instance, \code{b} cannot have dynamic type -\code{B{}>}, -because \code{Inv} is not a subtype of \code{Inv}.% -} - -\LMHash{}% -A raw type $T$ is a compile-time error if instantiation to bound on $T$ -yields a type which is not well-bounded -(\ref{superBoundedTypes}). - -\commentary{% -This kind of error can occur, as demonstrated by the following example:% -} - -\begin{dartCode} -\CLASS{} C{}> \{\} -\TYPEDEF{} F{}> = X \FUNCTION(X); -\\ -F f; // \comment{Compile-time error.} -\end{dartCode} - -\commentary{% -With these declarations, -the raw \code{F} which is used as a type annotation is a compile-time error: -The algorithm yields \code{F{}>}, -and that is neither a regular-bounded nor a super-bounded type. -% -The resulting type can be specified explicitly as -\code{C<\DYNAMIC{}> \FUNCTION(C<\DYNAMIC{}>)}. -That type exists, -we just cannot express it by passing a type argument to \code{F}, -so we make it an error rather than allowing it implicitly.% -} - -\rationale{% -The core reason why it makes sense to make such a raw type an error -is that there is no subtype relationship -between the relevant parameterized types.% -} -\commentary{% -For instance, \code{F} and \code{F} are unrelated, -even when \SubtypeNE{\code{T1}}{\code{T2}} or vice versa. -In fact, there is no type \code{T} whatsoever -such that a variable with declared type \code{F} -could be assigned to a variable of type -\code{C<\DYNAMIC{}> \FUNCTION(C<\DYNAMIC{}>)}. -% -So the raw \code{F}, if permitted, -would not be ``a supertype of \code{F} for all possible \code{T}'', -it would be a type which is unrelated to \code{F} -for \emph{every single} \code{T} that satisfies the bound of \code{F}. -This is so useless that we made it an error.% -} - -\LMHash{}% -When instantiation to bound is applied to a type, it proceeds recursively: -For a parameterized type \code{$G$<\List{T}{1}{k}>} -it is applied to \List{T}{1}{k}. -For a function type -\FunctionTypePositionalStd{T_0} - -\noindent -and a function type -\FunctionTypeNamedStd{T_0} -it is applied to \List{T}{0}{n+k}. - -\commentary{% -This means that instantiation to bound has no effect on -a type that does not contain any raw types. -Conversely, instantiation to bound acts on types which are syntactic subterms, -also when they are deeply nested.% -} - - -\section{Metadata} -\LMLabel{metadata} - -\LMHash{}% -Dart supports metadata which is used to attach user defined annotations to program structures. - -\begin{grammar} - ::= (`@' (`.' )? ?)* -\end{grammar} - -\LMHash{}% -Metadata consists of a series of annotations, -each of which begin with the character \lit{@}, -followed by a constant expression $e$ derivable from -\syntax{ (`.' )? ?}. -It is a compile-time error if $e$ is not one of the following: -\begin{itemize} -\item A reference to a constant variable. -\item A call to a constant constructor. -\end{itemize} - -\commentary{% -The expression $e$ occurs in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly. -} - -\LMHash{}% -Metadata is associated with the abstract syntax tree -of the program construct $p$ that immediately follows the metadata, -and which is not itself metadata or a comment. -Metadata can be retrieved at run time via a reflective call, -provided the annotated program construct $p$ is accessible via reflection. - -\commentary{ -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. -} - -\rationale{ -It is important that no run-time 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 implementations may skip the metadata during ordinary parsing and execution, -and evaluate it lazily. -} - -\commentary{ -It is possible to associate metadata with constructs -that may not be accessible via reflection, -such as local variables -(though it is conceivable that in the future, -richer reflective 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. -} - -\LMHash{}% -Metadata can appear before a library, part header, class, -typedef, type parameter, constructor, factory, function, -parameter, or variable declaration, -and before an import, export, or part directive. - -\LMHash{}% -The constant expression given in an annotation is type checked and evaluated -in the scope surrounding the declaration being annotated. - - -\section{Expressions} -\LMLabel{expressions} - -\LMHash{}% -An \Index{expression} is a fragment of Dart code -that can be evaluated at run time. - -\LMHash{}% -Every expression has an associated static type (\ref{staticTypes}) and -may have an associated static context type -%% TODO(eernst): This ref is undefined until CL 92782 is landed. -%% (\ref{contextTypes}), -which may affect the static type and evaluation of the expression. -Every value has an associated dynamic type (\ref{dynamicTypeSystem}). - -\begin{grammar} - ::= - \alt * - \alt - - ::= \gnewline{} - - \alt - \alt - - ::= (`,' )* - - ::= - \alt \SUPER{} - \alt - \alt - \alt - \alt - \alt - \alt `(' `)' -\end{grammar} - -\LMHash{}% -An expression $e$ may always be enclosed in parentheses, but this never has any semantic effect on $e$. - -\commentary{ -However, it may have an effect on the surrounding expression. -For instance, given a class \code{C} with a static method -\code{m() => 42}, \code{C.m()} returns 42, -but \code{(C).m()} is a compile-time error. -% -The point is that the meaning of \code{C.m()} -is specified in terms of several parts, -rather than being specified in a strictly compositional manner. -Concretely, the meaning of \code{C} and \code{(C)} as expressions is the same, -but the meaning of \code{C.m()} is not defined in terms of -the meaning of \code{C} as an expression, -and it differs from the meaning of \code{(C).m()}. -% A strictly compositional evaluation would always evaluate every subexpression -% using the same rules (`evaluation` is always the same thing), and then it -% would combine the evaluation results into the result of the whole expression. -% We won't expand on that here, and in particular we won't discuss whether -% compositional evaluation is even meaningful in the context of side-effects. -% But it's still useful to keep in mind that we have these "highly -% non-compositional" elements in the semantics, such as static method -% lookups. -} - - -\subsection{Expression Evaluation} -\LMLabel{expressionEvaluation} - -\LMHash{}% -Evaluation of an expression either -\IndexCustom{produces an object}{expression!produces an object} -or it -\IndexCustom{throws}{expression!throws} -an exception object and an associated stack trace. -In the former case, we also say that the expression -\NoIndex{evaluates to an object}. - -\LMHash{}% -If evaluation of one expression, $e$, -is defined in terms of evaluation of another expression $e_1$, -typically a subexpression of $e$, -and the evaluation of $e_1$ throws an exception and a stack trace, -the evaluation of $e$ stops at that point -and throws the same exception object and stack trace. - - -\subsection{Object Identity} -\LMLabel{objectIdentity} - -\LMHash{}% -The predefined Dart function \code{identical()} is defined such that \code{identical($c_1$, $c_2$)} if{}f: -\begin{itemize} -\item $c_1$ evaluates to either the null object (\ref{null}) or an instance of \code{bool} and \code{$c_1$ == $c_2$}, OR -\item $c_1$ and $c_2$ are instances of \code{int} and \code{$c_1$ == $c_2$}, OR -\item $c_1$ and $c_2$ are constant strings and \code{$c_1$ == $c_2$}, OR -\item $c_1$ and $c_2$ are instances of \code{double} and one of the following holds: - \begin{itemize} - \item $c_1$ and $c_2$ are non-zero and \code{$c_1$ == $c_2$}. - \item Both $c_1$ and $c_2$ are $+0.0$. - \item Both $c_1$ and $c_2$ are $-0.0$. - \item Both $c_1$ and $c_2$ represent a NaN value with the same underlying bit pattern. - \end{itemize} - OR -\item $c_1$ and $c_2$ are constant lists that are defined to be identical in the specification of literal list expressions (\ref{lists}), OR -\item $c_1$ and $c_2$ are constant maps that are defined to be identical in the specification of literal map expressions (\ref{maps}), OR -\item $c_1$ and $c_2$ are constant objects of the same class $C$ and the value of each instance variable of $c_1$ is identical to the value of the corresponding instance variable of $c_2$. OR -\item $c_1$ and $c_2$ are the same object. -\end{itemize} - -\commentary{ -The definition of \code{identity} for doubles differs from that of equality in that a NaN is identical to itself, and that negative and positive zero are distinct. -} - -\rationale{ -The definition of equality for doubles is dictated by the IEEE 754 standard, which posits that NaNs do not obey the law of reflexivity. -Given that hardware implements these rules, it is necessary to support them for reasons of efficiency. - -The definition 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. -} - - -\subsection{Constants} -\LMLabel{constants} - -\commentary{ -All usages of the word 'constant' in Dart are associated with compile time. -A potentially constant expression is an expression that will generally yield -a constant value when the value of certain parameters is given. -The constant expressions is a subset of the potentially constant expressions -that \emph{can} be evaluated entirely at compile time. -} - -\rationale{ -The constant expressions are restricted to expressions that -perform only simple arithmetic operations, boolean conditions, and string and instance creation. -No user written function body is executed during constant expression evaluation, -only members of the system classes \code{int}, \code{double}, \code{bool}, \code{String} or \code{Null}. -} - -\LMHash{}% -The \IndexCustom{potentially constant expressions}{% - potentially constant expression} -and \IndexCustom{constant expressions}{constant expression} -are the following: - -\begin{itemize} -\item A literal boolean, \TRUE{} or \FALSE{} (\ref{booleans}), is a potentially constant and constant expression. - -\item A literal number (\ref{numbers}) is a potentially constant and constant expression - if it evaluates to an instance of type \code{int} or \code{double}. - % A too-large integer literal does not evaluate to an object. - -\item A literal string (\ref{strings}) with string interpolations - (\ref{stringInterpolation}) - with expressions $e_1$, \ldots{}, $e_n$ is a potentially constant expression - if $e_1$, \ldots{}, $e_n$ are potentially constant expressions. - The literal is further a constant expression - if $e_1$, \ldots{}, $e_n$ are constant expressions - evaluating to instances of \code{int}, \code{double} \code{String}, \code{bool} or \code{Null}. -\commentary{These requirements hold trivially if there are no interpolations in the string}. -\rationale{It would be tempting to allow string interpolation where the -interpolated value is any compile-time constant. However, this would require -running the \code{toString()} method for constant objects, which could contain -arbitrary code.} - -\item A literal symbol (\ref{symbols}) is a potentially constant and constant expression. - -\item The literal \NULL{} (\ref{null}) is a potentially constant and constant expression. - -\item An identifier that denotes a constant variable is a potentially constant and constant expression. - -\item A qualified reference to a static constant variable (\ref{variables}) that is not qualified by a deferred prefix, is a potentially constant and constant expression. -\commentary{ -For example, If class $C$ declares a constant static variable $v$, \code{$C$.$v$} is a constant. -The same is true if $C$ is accessed via a prefix $p$; \code{$p$.$C$.$v$} is a constant unless $p$ is a deferred prefix. -} - -\item A simple or qualified identifier denoting a class, a mixin or a type alias that is not qualified by a deferred prefix, is a potentially constant and constant expression. -\commentary{ -The constant expression always evaluates to a \code{Type} object. -For example, if $C$ is the name of a class or type alias, the expression \code{$C$} is a constant, and if $C$ is imported with a prefix $p$, \code{$p$.$C$} is a constant \code{Type} instance representing the type of $C$ unless $p$ is a deferred prefix. -} - -\item A simple or qualified identifier denoting a top-level function (\ref{functions}) or a static method (\ref{staticMethods}) that is not qualified by a deferred prefix, is a potentially constant and constant expression. - -\item An identifier expression denoting a parameter of a constant constructor (\ref{constantConstructors}) that occurs in the initializer list of the constructor, is a potentially constant expression. - -\item A constant object expression (\ref{const}), -\code{\CONST{} $C$<$T_1,\ \ldots,\ T_k$>(\metavar{arguments})} or -\code{\CONST{} $C$<$T_1,\ \ldots,\ T_k$>.\id(\metavar{arguments})}, -or either expression without the leading \CONST{} that occurs in a constant context, is a potentially constant expression. -It is further a constant expression if the invocation evaluates to an object. -% \ref{const} requires each actual argument to be a constant expression, -% but here we also catch errors during evaluation, e.g., `C(1, 0)` where -% `C(double x, double y): z = x / y;`. -It is a compile-time error if a constant object expression is -not a constant expression (\ref{const}). - -\item A constant list literal (\ref{lists}), -\code{\CONST{} <$T$>[$e_1$, \ldots{}, $e_n$]}, or -\code{<$T$>[$e_1$, \ldots{}, $e_n$]} -that occurs in a constant context, is a potentially constant expression if $T$ is a constant type expression, and $e_1$, \ldots{} , $e_n$ are constant expressions. -It is further a constant expression if the list literal evaluates to an object. - -\item A constant set literal (\ref{set}), -\code{\CONST{} <$T$>\{$e_1$, \ldots{}, $e_n$\}}, or -\code{<$T$>\{$e_1$, \ldots{}, $e_n$\}} -that occurs in a constant context, is a potentially constant expression if $T$ is a constant type expression, and $e_1$, \ldots{} , $e_n$ are constant expressions. -It is further a constant expression if the list literal evaluates to an object. - -\item A constant map literal (\ref{maps}), -\code{\CONST{} <$K$, $V$>\{$k_1$: $v_1$, \ldots{}, $k_n$: $v_n$\}}, or -\code{<$K$, $V$>\{$k_1$: $v_1$, \ldots{}, $k_n$: $v_n$\}} that occurs in a constant context, -is a potentially constant expression. -It is further a constant expression if the map literal evaluates to an object. - -\item A parenthesized expression \code{($e$)} is a potentially constant expression if $e$ is a potentially constant expression. It is further a constant expression if $e$ is a constant expression. - -\item An expression of the form \code{identical($e_1$, $e_2$)} is a potentially constant expression if $e_1$ and $e_2$ are potentially constant expressions and \code{identical} is statically bound to the predefined dart function \code{identical()} discussed above (\ref{objectIdentity}). It is further a constant expression if $e_1$ and $e_2$ are constant expressions. - -\item An expression of the form \code{$e_1$\,!=\,$e_2$} is equivalent to \code{!($e_1$\,==\,$e_2$)} in every way, including whether it is potentially constant or constant. - -\item An expression of the form \code{$e_1$\,==\,$e_2$} is potentially constant - if $e_1$ and $e_2$ are both potentially constant expressions. - It is further constant if both $e_1$ and $e_2$ are constant and - either $e_1$ evaluates to an object that is an instance of - \code{int}, \code{double}, \code{String}, \code{bool} or \code{Null}, - or if $e_2$ evaluates to the null object (\ref{null}). - %TODO: Consider adding enum instances here. - -\item An expression of the form \code{!$e_1$} is potentially constant if $e_1$ is potentially constant. It is further constant if $e_1$ is a constant expression that evaluates to an instance of type \code{bool}. - -\item An expression of the form \code{$e_1$\,\&\&\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if $e_1$ is a constant expression and either -\begin{enumerate} -\item $e_1$ evaluates to \FALSE{}, or -\item $e_1$ evaluates to \TRUE{} and $e_2$ is a constant expression that evaluates to an instance of type \code{bool}. -\end{enumerate} - -\item An expression of the form \code{$e_1$\,||\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if $e_1$ is a constant expression and either -\begin{enumerate} -\item $e_1$ evaluates to \TRUE{}, or -\item $e_1$ evaluates to \FALSE{} and $e_2$ is a constant expression that evaluates to an instance of type \code{bool}. -\end{enumerate} - -\item An expression of the form \code{\~{}$e_1$} is a potentially constant expression if $e_1$ is a potentially constant expression. It is further a constant expression if $e_1$ is a constant expression that evaluates to an instance of type \code{int}. - -\item An expression of one of the forms \code{$e_1$\,\&\,$e_2$}, - \code{$e_1$\,|\,$e_2$}, or \code{$e_1$\,\^\,$e_2$} is potentially constant - if $e_1$ and $e_2$ are both potentially constant expressions. - It is further constant if both $e_1$ and $e_2$ are constant expressions that - both evaluate to instances of \code{int}, or both to instances of \code{bool}. - % The bool case is new in 2.1. - -\item An expression of one of the forms \code{$e_1$\,\~{}/\,$e_2$}, - \code{$e_1$\,\gtgt\,$e_2$}, \code{$e_1$\,\gtgtgt\,$e_2$}, - or \code{$e_1$\,\ltlt\,$e_2$} is potentially constant - if $e_1$ and $e_2$ are both potentially constant expressions. - It is further constant if both $e_1$ and $e_2$ are constant expressions that - both evaluate to an instance of \code{int}. - -\item An expression of the form \code{$e_1$\,+\,$e_2$} is - a potentially constant expression if $e_1$ and $e_2$ - are both potentially constant expressions. - It is further a constant expression if both $e_1$ and $e_2$ are constant expressions - and either both evaluate to an instance of \code{int} or \code{double}, - or both evaluate to an instance of \code{String}. - -\item An expression of the form \code{-$e_1$} is a potentially constant expression - if $e_1$ is a potentially constant expression. - It is further a constant expression if $e_1$ is a constant expression that - evaluates to an instance of type \code{int} or \code{double}. - -\item An expression of the form \code{$e_1$\,-\,$e_2$}, \code{$e_1$\,*\,$e_2$}, - \code{$e_1$\,/\,$e_2$}, \code{$e_1$\,\%\,$e_2$}, \code{$e_1$\,<\,$e_2$}, - \code{$e_1$\,<=\,$e_2$}, \code{$e_1$\,>\,$e_2$}, or \code{$e_1$\,>=\,$e_2$} - is potentially constant - if $e_1$ and $e_2$ are both potentially constant expressions. - It is further constant if both $e_1$ and $e_2$ are constant expressions that - evaluate to instances of \code{int} or \code{double}. - -\item An expression of the form \code{$e_1$\,?\,$e_2$\,:\,$e_3$} - is potentially constant if $e_1$, $e_2$, and $e_3$ - are all potentially constant expressions. - It is constant if $e_1$ is a constant expression and either -\begin{enumerate} -\item $e_1$ evaluates to \TRUE{} and $e_2$ is a constant expression, or -\item $e_1$ evaluates to \FALSE{} and $e_3$ is a constant expression. -\end{enumerate} - -\item An expression of the form \code{$e_1$\,??\,$e_2$} is potentially constant - if $e_1$ and $e_2$ are both potentially constant expressions. - It is further constant if $e_1$ is a constant expression and either -\begin{enumerate} -\item $e_1$ evaluates to an object which is not the null object, or -\item $e_1$ evaluates to the null object, and $e_2$ is a constant expression. -\end{enumerate} - -\item An expression of the form \code{$e$.length} is potentially constant - if $e$ is a potentially constant expression. - It is further constant if $e$ is a constant expression that - evaluates to an instance of \code{String}. - -% New in 2.1. -\item An expression of the form \code{$e$ as $T$} is potentially constant - if $e$ is a potentially constant expression - and $T$ is a constant type expression, - and it is further constant if $e$ is constant. -\commentary{ -It is a compile-time error to evaluate the constant expression -if the cast operation would throw, that is, -if $e$ evaluates to an object which is not the null object and not of type $T$. -} - -% New in 2.1. -\item An expression of the form \code{$e$ is $T$} is potentially constant - if $e$ is a potentially constant expression - and $T$ is a constant type expression, - and it is further constant if $e$ is constant. - -% New in 2.1. -\item{} - An expression of the form \code{$e$ is! $T$} - is equivalent to \code{!($e$ is $T$)} in every way, - including whether it's potentially constant or constant. -\end{itemize} - -\LMHash{}% -% New in 2.1. -A -\Index{constant type expression} -is one of: -\begin{itemize} -\item An simple or qualified identifier - denoting a type declaration (a type alias, class or mixin declaration) - that is not qualified by a deferred prefix, - optionally followed by type arguments of the form - \code{<$T_1$,\ \ldots,\ $T_n$>} - where $T_1$, \ldots{}, $T_n$ are constant type expressions. -\item A type of the form \code{FutureOr<$T$>} - where $T$ is a constant type expression. -\item - %% TODO(eernst): This does not allow for type variables introduced by - %% the type itself. `Function(X)` could be a constant type expression, - %% but that is not covered by the current rules: `X` is a type variable, - %% and they are never allowed. - A function type - \code{$R$ Function<\metavar{typeParameters}>(\metavar{argumentTypes})} - (where $R$ and \code{<\metavar{typeParameters}>} may be omitted) - and where $R$, \metavar{typeParameters} and \metavar{argumentTypes} - (if present) contain only constant type expressions. -\item The type \VOID{}. -\item The type \DYNAMIC{}. -\end{itemize} - -% Being potentially constant is entirely structural, not type based, -% but the program still has to satisfy strong-mode typing. - -% Constant expressions (like "const Foo(42)") always evaluate to the -% same value, with at most one value per source location. -% Potentially constant expressions that are not constant only -% allow simple operations on basic types (num, String, bool, Null). These can -% be computed statically without running user code. - -% A validly typed potentially constant expression can still fail when evaluated. -% If that happens in a const invociation, it's a compile-time error. - -\LMHash{}% -It is a compile-time error if an expression is required to be a constant expression but its evaluation would throw an exception. -It is a compile-time error if an assertion is evaluated as part of a constant object expression evaluation, and the assertion would throw an exception. - -\commentary{ -Note that there is no requirement that every constant expression evaluate correctly. -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-flow. -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 throw 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. -} - -\begin{dartCode} -\CONST{} x = 1 \~{}/ 0; -\FINAL{} y = 1 \~{}/ 0; -\\ -\CLASS{} K \{ - m1() \{ - \VAR{} z = \FALSE{}; - \IF{} (z) \{ \RETURN{} x; \} - \ELSE{} \{ \RETURN{} 2; \} - \} -\\ - m2() \{ - \IF{} (\TRUE{}) \{ \RETURN{} y; \} - \ELSE{} \{ \RETURN{} 3; \} - \} -\} -\end{dartCode} - -\commentary{ -An implementation is free to immediately issue a compilation error for \code{x}, but it is not required to do so. -It could defer errors if it does not immediately compile the declarations that reference \code{x}. -For example, it could delay giving a compilation error about the method \code{m1} until the first invocation of \code{m1}. -However, it could not choose to execute \code{m1}, see that the branch that refers to \code{x} is not taken and return 2 successfully. - -The situation with respect to an invocation \code{m2} is different. -Because \code{y} is not a compile-time constant (even though its value is), one need not give a compile-time error upon compiling \code{m2}. -An implementation may run the code, which will cause the getter for \code{y} to be invoked. -At that point, the initialization of \code{y} must take place, which requires the initializer to be compiled, which will cause a compilation error. -} - -\rationale{ -The treatment of \code{\NULL{}} merits some discussion. -Consider \code{\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 \code{\NULL{}} as a subexpression of numeric or boolean constant expressions). -There are two arguments for including it: -\begin{enumerate} -\item It is constant. -We can evaluate it at compile time. -\item It seems more useful to give the error stemming from the evaluation explicitly. -\end{enumerate} -} - -\rationale{ -One might reasonably ask why $e_1$\,?\,$e_1$\,:\,$e_3$ and $e_1$\,??\,$e_2$ have constant forms. -For example, if $e_1$ is known statically, why do we need to test it? -The answer is that there are contexts where $e_1$ is a variable. -In particular, constant constructor initializers such as - -\code{\CONST{} C(foo): \THIS.foo = foo ?? someDefaultValue;} -} - -\LMHash{}% -It is a compile-time error if the value of a constant expression depends on itself. - -\commentary{ -As an example, consider: -} - -\begin{dartCode} -\CLASS{} CircularConsts \{ - // \comment{Illegal program - mutually recursive compile-time constants} - \STATIC{} \CONST{} i = j; // \comment{a compile-time constant} - \STATIC{} \CONST{} j = i; // \comment{a compile-time constant} -\} -\end{dartCode} - -\begin{grammar} - ::= - \alt - \alt - \alt - \alt - \alt - \alt - \alt - \alt -\end{grammar} - - -\subsubsection{Constant Contexts} -\LMLabel{constantContexts} - -\LMHash{}% -Let $e$ be an expression; $e$ occurs in a -\Index{constant context} -if{}f one of the following applies: - -% We avoid the circularity "constant context depends on constant list literal, -% etc., which depends on constant context" by mentioning the \CONST{} modifier -% explicitly here. So 'constant context' is consistently a lower-level concept -% based on syntax, and 'constant X expressions' (like 'constant list literal') -% are built on top of this. - -\begin{itemize} -\item $e$ is an element of a list or set literal whose first token is \CONST, - or $e$ is a key or a value of an entry - of a map literal whose first token is \CONST. -\item $e$ occurs as \code{@$e$} in a construct derived from \synt{metadata}. -\item $e$ is an actual argument in an expression derived from - \synt{constObjectExpression}. -\item $e$ is the initializing expression of a constant variable declaration - (\ref{variables}). -\item $e$ is a switch case expression - (\ref{switch}). -\item $e$ is an immediate subexpression of - an expression $e_0$ which occurs in a constant context, - where $e_0$ is - %% May be added later: - %% not a \THROW{} expression (\ref{throw}) and - not a function literal - (\ref{functionExpressions}). -\end{itemize} - -\rationale{% -A constant context is introduced in situations where -an expression is required to be constant. -This is used to allow the \CONST{} modifier to be omitted -in cases where it does not contribute any new information.% -} - - -\subsection{Null} -\LMLabel{null} - -\LMHash{}% -The reserved word \NULL{} evaluates to the \Index{null object}. - -\begin{grammar} - ::= \NULL{} -\end{grammar} - -\LMHash{}% -The null object is the sole instance of the built-in class \code{Null}. -% The following can be a consequence of the declaration of `Null`, -% but we don't spell that out, we just require that it is an error. -Attempting to instantiate \code{Null} causes a compile-time error. -It is a compile-time error for a class to extend, mix in or implement \code{Null}. -The \code{Null} class extends the \code{Object} class and declares no methods except those also declared by \code{Object}. -In particular, the \code{Null} class does not override the \lit{==} operator -inherited from the \code{Object} class. - -\LMHash{}% -The static type of \NULL{} is the \code{Null} type. - - -\subsection{Numbers} -\LMLabel{numbers} - -\LMHash{}% -A \IndexCustom{numeric literal}{literal!numeric} -is either a decimal or hexadecimal numeral representing an integer value, or a decimal double representation. - -\begin{grammar} - ::= - \alt - - ::= + (`.' +)? ? - \alt `.' + ? - - ::= (`e' | `E') (`+' | `-')? + - - ::= `0x' + - \alt `0X' + - - ::= `a' .. `f' - \alt `A' .. `F' - \alt -\end{grammar} - -\LMHash{}% -A numeric literal starting with `0x' or `0X' -is a \IndexCustom{hexadecimal integer literal}{literal!hexadecimal integer}. -It has the numeric integer value of the hexadecimal numeral -following `0x' (respectively `0X'). - -\LMHash{}% -A numeric literal that contains only decimal digits is a -\IndexCustom{decimal integer literal}{literal!decimal integer}. -It has the numeric integer value of the decimal numeral. - -\LMHash{}% -An \IndexCustom{integer literal}{literal!integer} -is either a hexadecimal integer literal or a decimal integer literal. - -\LMHash{}% -Let $l$ be an integer literal that is not the operand -of by a unary minus operator, -and let $T$ be the static context type of $l$. -If \code{double} is assignable to $T$ and \code{int} is not assignable to $T$, -then the static type of $l$ is \code{double}; -otherwise the static type of $l$ is \code{int}. -\commentary{ - This means that an integer literal denotes a \code{double} - when it would satisfy the type requirement, and an \code{int} would not. Otherwise it is an \code{int}, even in situations where that is an error. -} - -\LMHash{}% -A numeric literal that is not an integer literal is a -\IndexCustom{double literal}{literal!double}. -\commentary{A double literal always contains either a decimal point or an exponent part.} -The static type of a double literal is \code{double}. - -\LMHash{}% -If $l$ is an integer literal with numeric value $i$ and static type \code{int}, -and $l$ is not the operand of a unary minus operator, -then evaluation of $l$ proceeds as follows: -\begin{itemize} - \item{} If $l$ is a hexadecimal integer literal, - $2^{63} \le i < 2^{64}$ and the \code{int} class is implemented as - signed 64-bit two's complement integers, - then $l$ evaluates to an instance of the \code{int} class - representing the numeric value $i - 2^{64}$, - \item{} Otherwise $l$ evaluates to an instance of the \code{int} class - representing the numeric value $i$. - It is a compile-time error if the integer $i$ cannot be represented - exactly by an instance of \code{int}. -\end{itemize} - -\commentary{ -Integers in Dart are designed to be implemented as -64-bit two's complement integer representations. -In practice, implementations may be limited by other considerations. -For example, Dart compiled to JavaScript may use the JavaScript number type, -equivalent to Dart \code{double}, to represent integers, and if so, -integer literals with more than 53 bits of precision cannot be represented -exactly. -} - -\LMHash{}% -A double literal evaluates to a an instance of the \code{double} class -representing a 64 bit double precision floating point number -as specified by the IEEE 754 standard. - -\LMHash{}% -An integer literal with static type \code{double} and numeric value $i$ -evaluates to an instance of the \code{double} class representing -the value $i$. It is a compile-time error if the value $i$ cannot be -represented \emph{precisely} by the an instance of \code{double}. -\commentary{ -A 64 bit double precision floating point number -is usually taken to represent a range of real numbers -around the precise value denoted by the number's -sign, mantissa and exponent. -For integer literals evaluating to \code{double} -values we insist that the integer literal's numeric value -is the precise value of the \code{double} instance. -} - -\LMHash{}% -It is a compile-time error for a class to extend, mix in or implement \code{int}. -It is a compile-time error for a class to extend, mix in or implement \code{double}. -It is a compile-time error for any class other than \code{int} and \code{double} to extend, mix in or implement \code{num}. - -\LMHash{}% -The instances of \code{int} and \code{double} all override the \lit{==} operator inherited from the \code{Object} class. - - -\subsection{Booleans} -\LMLabel{booleans} - -\LMHash{}% -The reserved words \TRUE{} and \FALSE{} evaluate to objects -\IndexCustom{true}{true, the object} and -\IndexCustom{false}{false, the object} -that represent the boolean values true and false respectively. -They are the \IndexCustom{boolean literals}{literal!boolean}. - -\begin{grammar} - ::= \TRUE{} - \alt \FALSE{} -\end{grammar} - -\LMHash{}% -Both \NoIndex{true} and \NoIndex{false} are instances of -the built-in class \code{bool}, -and there are no other objects that implement \code{bool}. -It is a compile-time error for a class to -extend, mix in or implement \code{bool}. - -\LMHash{}% -The \code{bool} class does not override the \lit{==} operator inherited from -the \code{Object} class. - -\LMHash{}% -Invoking the getter \code{runtimeType} on a boolean value returns the \code{Type} object that is the value of the expression \code{bool}. -The static type of a boolean literal is \code{bool}. - - -\subsection{Strings} -\LMLabel{strings} - -\LMHash{}% -A \Index{string} is a sequence of UTF-16 code units. - -\rationale{ -This decision was made for compatibility with web browsers and Javascript. -Earlier versions of the specification required a string to be a sequence of valid Unicode code points. -Programmers should not depend on this distinction. -} - -\begin{grammar} - ::= ( | )+ -\end{grammar} - -\LMHash{}% -A string can be a sequence of single line strings and multiline strings. - -\begin{grammar} - ::= `"' * `"' - \alt `\'' * `\'' - \alt `r\'' (\~{}( `\'' | ))* `\'' - \alt `r"' (\~{}( `"' | ))* `"' -\end{grammar} - -\LMHash{}% -A single line string is delimited by either matching single quotes or matching double quotes. - -\commentary{ -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' didn't he''. -However ``This ` is not a valid string, nor is `this''. -} - -\commentary{ -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. -} - -\LMHash{}% -Adjacent strings are implicitly concatenated to form a single string literal. - -\commentary{ -Here is an example -} - -\begin{dartCode} -print("A string" "and then another"); // \comment{A stringand then another} -\end{dartCode} - -\rationale{ -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 -} - -\begin{dartCode} -print("A simple sum: 2 + 2 = " + - 2 + 2); -\end{dartCode} - -\rationale{ -which this prints 'A simple sum: 2 + 2 = 22' rather than 'A simple sum: 2 + 2 = 4'. -However, the use of the concatenation operation is still discouraged for efficiency reasons. -Instead, the recommended Dart idiom is to use string interpolation. -} - -\begin{dartCode} -print("A simple sum: 2 + 2 = \$\{2+2\}"); -\end{dartCode} - -\rationale{ -String interpolation works well for most cases. -The main situation where it is not fully satisfactory is for string literals that are too large to fit 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: -} - -\begin{dartCode} -'Imagine this is a very long string that does not fit on a line. What shall we do? ' -'Oh what shall we do? ' -'We shall split it into pieces ' -'like so'. -\end{dartCode} - -\begin{grammar} - ::= `"""' * `"""' - \alt `\'\mbox\'\mbox\'' * `\'\mbox\'\mbox\'' - \alt `r"""' (\~{} `"""')* `"""' - \alt `r\'\mbox\'\mbox\'' (\~{} `\'\mbox\'\mbox\'')* `\'\mbox\'\mbox\'' - - ::= `\\n' - \alt `\\r' - \alt `\\f' - \alt `\\b' - \alt `\\t' - \alt `\\v' - \alt `\\x' - \alt `\\u' - \alt `\\u{' `}' - - ::= \gnewline{} - ? ? - \gnewline{} ? ? ? -\end{grammar} - -\LMHash{}% -Multiline strings are delimited by either -matching triples of single quotes or -matching triples of double quotes. -If the first line of a multiline string consists solely of -the whitespace characters defined by the production \synt{WHITESPACE} -(\ref{lexicalRules}), -possibly prefixed by \syntax{`\\'}, -then that line is ignored, -including the line break at its end. - -\rationale{ -The idea is to ignore a whitespace-only first line of a multiline string, where whitespace is defined as tabs, spaces and the final line break. -These can be represented directly, but since for most characters prefixing by backslash is an identity in a non-raw string, we allow those forms as well. -} - - % could be clearer. Is the first line in """\t - % """ ignored not. It depends if we mean whitespace before escapes are interpreted, - % or after, or both. See https://code.google.com/p/dart/issues/detail?id=23020 - -\LMHash{}% -Strings support escape sequences for special characters. -The escapes are: -\begin{itemize} -\item - \syntax{`\\n'} for newline, equivalent to \syntax{`\\x0A'}. -\item - \syntax{`\\r'} for carriage return, equivalent to \syntax{`\\x0D'}. -\item - \syntax{`\\f'} for form feed, equivalent to \syntax{`\\x0C'}. -\item - \syntax{`\\b'} for backspace, equivalent to \syntax{`\\x08'}. -\item - \syntax{`\\t'} for tab, equivalent to \syntax{`\\x09'}. -\item - \syntax{`\\v'} for vertical tab, equivalent to \syntax{`\\x0B'}. -\item - \syntax{`\\x' $_1$ $_2$}, equivalent to - - \syntax{`\\u{' $_1$ $_2$ `}'}. -\item - \syntax{`\\u' $_1$ $_2$ $_3$ $_4$}, - equivalent to - - \noindent - \syntax{`\\u{' $_1$ $_2$ $_3$ $_4$ `}'}. -\item - \syntax{`\\u{' `}'} is - the Unicode code point represented by the - \syntax{}. - It is a compile-time error if the value of the - \syntax{} - is not a valid Unicode code point. -\item - \lit{\$} indicating the beginning of an interpolated expression. -\item - Otherwise, \syntax{`\\$k$'} indicates the character $k$ for - any $k$ not in \syntax{$\{$`n', `r', `f', `b', `t', `v', `x', `u'$\}$}. -\end{itemize} - -\LMHash{}% -Any string may be prefixed with the character \lit{r}, -indicating that it is a \Index{raw string}, -in which case no escapes or interpolations are recognized. - -\LMHash{}% -Line breaks in a multiline string are represented by -the \syntax{} production. -A line break introduces a single newline character into the string value. - -\LMHash{}% -It is a compile-time error if a non-raw string literal contains -a character sequence of the form \syntax{`\\x'} that is not followed by -a sequence of two hexadecimal digits. -It is a compile-time error if a non-raw string literal contains -a character sequence of the form \syntax{`\\u'} that is not followed by -either a sequence of four hexadecimal digits, -or by curly brace delimited sequence of hexadecimal digits. - -\begin{grammar} - ::= \~{}( `\\' | `"' | `$' | ) - \alt `\\' \~{}( ) - \alt - - ::= \~{}( `\\' | `\'' | `$' | ) - \alt `\\' \~{}( ) - \alt - - ::= \~{}( `\\' | `"""' | `$') - \alt `\\' \~{}( ) - \alt - - ::= \~{}( `\\' | `\'\'\'' | `$') - \alt `\\' \~{}( ) - \alt - - ::= `\\n' - \alt `\\r' - \alt `\\r\\n' -\end{grammar} - -\LMHash{}% -All string literals evaluate to instances of the built-in class \code{String}. -It is a compile-time error for a class to -extend, mix in or implement \code{String}. -The \code{String} class overrides the \lit{==} operator inherited from -the \code{Object} class. -The static type of a string literal is \code{String}. - - -\subsubsection{String Interpolation} -\LMLabel{stringInterpolation} - -\LMHash{}% -It is possible to embed expressions within non-raw string literals, -such that these expressions are evaluated, -and the resulting values are converted into strings and -concatenated with the enclosing string. -This process is known as \Index{string interpolation}. - -\begin{grammar} - ::= `$' - \alt `${' `}' -\end{grammar} - -\commentary{ -The reader will note that the expression inside the interpolation -could itself include strings, -which could again be interpolated recursively. -} - -\LMHash{}% -An unescaped \lit{\$} character in a string signifies -the beginning of an interpolated expression. -The \lit{\$} sign may be followed by either: -\begin{itemize} -\item A single identifier \id{} that does not contain the \lit{\$} character. -\item An expression $e$ delimited by curly braces. -\end{itemize} - -\LMHash{}% -The form \code{\$\id} is equivalent to the form \code{\$\{\id\}}. -An interpolated string, $s$, with content -`\code{$s_0$\$\{$e_1$\}$s_1\ldots{}s_{n-1}$\$\{$e_n$\}$s_{n}$}' (where any of $s_0, \ldots, s_n$ can be empty) -is evaluated by evaluating each expression $e_i$ ($1 \le i \le n$) in to a string $r_i$ in the order they occur in the source text, as follows: -\begin{itemize} -\item{} Evaluate $e_i$ to an object $o_i$. -\item{} Invoke the \code{toString} method on $o_i$ with no arguments, and let - $r_i$ be the returned value. -\item{} If $r_i$ is not an instance of the built-in type \code{String}, throw an \code{Error}. -\end{itemize} -Finally, the result of the evaluation of $s$ is the concatenation of the strings $s_0$, $r_1$, \ldots, $r_n$, and $s_n$. - - -\subsection{Symbols} -\LMLabel{symbols} - -\LMHash{}% -A \IndexCustom{symbol literal}{literal!symbol} -denotes a name that would be either -a valid declaration name or a valid library name in a Dart program. - -\begin{grammar} - ::= `#' ( | ( (`.' )*)) -\end{grammar} - -\LMHash{}% -A symbol literal \code{\#\id} where \id{} is an identifier -that does not begin with an underscore (`\code{\_}'), -evaluates to an instance of \code{Symbol} representing the identifier \id. -All occurrences of \code{\#\id} evaluate to the same instance -\commentary{(symbol instances are canonicalized)}, -and no other symbol literals evaluate to that \code{Symbol} instance -or to a \code{Symbol} instance that is equal -(according to the \lit{==} operator \ref{equality}) to that instance. - -\LMHash{}% -A symbol literal \code{\#$\id.\id_2\ldots\id_n$} -where $\id{} \ldots \id_n$ are identifiers, -evaluates to an instance of \code{Symbol} representing that particular sequence of identifiers. -All occurrences of \code{\#$\id.\id_2\ldots\id_n$} with the same sequence of identifiers -evaluate to the same instance, -and no other symbol literals evaluate to that \code{Symbol} instance -or to a \code{Symbol} instance that is \lit{==} to that instance. -\commentary{This kind of symbol literal denotes the name of a library declaration. Library names are not subject to library privacy, even -if some of its identifiers begin with an underscore.} - -\LMHash{}% -A symbol literal \code{\#\metavar{operator}} evaluates to an instance of \code{Symbol} -representing that particular operator name. -All occurrences of \code{\#\metavar{operator}} evaluate to the same instance, -and no other symbol literals evaluate to that \code{Symbol} instance -or to a \code{Symbol} instance that is \lit{==} to that instance. - -\LMHash{}% -A symbol literal \code{\#\_\id}, evaluates to an instance of \code{Symbol} -representing the private identifier \code{\_\id} of the containing library. -All occurrences of \code{\#\_\id} \emph{in the same library} evaluate to the same instance, -and no other symbol literals evaluate to that \code{Symbol} instance -or to a \code{Symbol} instance that is \lit{==} to that instance. - -\LMHash{}% -The objects created by symbol literals all override -the \lit{==} operator inherited from the \code{Object} class. - -\rationale{ -One may well ask what is the motivation for introducing literal symbols? In some languages, symbols are canonicalized whereas strings are not. -However literal strings are already canonicalized in Dart. -Symbols are slightly easier to type compared to strings and their use can become strangely addictive, but this is not nearly sufficient justification for adding a literal form to the language. -The primary motivation is related to the use of reflection and a web specific practice known as minification. - -Minification compresses identifiers consistently throughout a program in order to reduce download size. -This practice poses difficulties for reflective programs that refer to program declarations via strings. -A string will refer to an identifier in the source, but the identifier will no longer be used in the minified code, and reflective code using these would fail. -Therefore, Dart reflection uses objects of type \code{Symbol} rather than strings. -Instances of \code{Symbol} are guaranteed to be stable with respect to minification. -Providing a literal form for symbols makes reflective code easier to read and write. -The fact that symbols are easy to type and can often act as convenient substitutes for enums are secondary benefits. -} - -\LMHash{}% -The static type of a symbol literal is \code{Symbol}. - - -\subsection{Lists} -\LMLabel{lists} - -\LMHash{}% -A \IndexCustom{list literal}{literal!list} -denotes a list, which is an integer indexed collection of objects. - -\begin{grammar} - ::= \CONST{}? ? `[' ( `,'?)? `]' -\end{grammar} - -\LMHash{}% -A list may contain zero or more objects. -The number of elements in a list is its size. -A list has an associated set of indices. -An empty list has an empty set of indices. -A non-empty list has the index set $\{0, \ldots, n - 1\}$ where $n$ is the size of the list. -It is a dynamic error to attempt to access a list -using an index that is not a member of its set of indices. - -\LMHash{}% -If a list literal $\ell$ begins with the reserved word \CONST{} -or $\ell$ occurs in a constant context -(\ref{constantContexts}), -it is a -\IndexCustom{constant list literal}{literal!list!constant}, -which is a constant expression -(\ref{constants}) -and therefore evaluated at compile time. -Otherwise, it is a -\IndexCustom{run-time list literal}{literal!list!run-time} -and it is evaluated at run time. -Only run-time list literals can be mutated -after they are created. -% This error can occur because being constant is a dynamic property, here. -Attempting to mutate a constant list literal will result in a dynamic error. - -\commentary{% -% The following is true either directly or indirectly: There is a \CONST{} -% modifier on the literal list, or we use the "immediate subexpression" rule -% about constant contexts. -Note that the element expressions of a constant list literal -occur in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly.% -} - -\LMHash{}% -It is a compile-time error if an element of a constant list literal -is not a constant expression. -It is a compile-time error if the type argument of a constant list literal -is not a constant type expression. - -\rationale{% -The binding of a formal type parameter is not known at compile time, -so we cannot use type parameters inside constant expressions.% -} - -\LMHash{}% -The value of a constant list literal -\code{\CONST?\,\,<$E$>[$e_1, \ldots, e_n$]} -is an object $a$ whose class implements the built-in class -\code{List<$E$>}. -Let $v_i$ be the value of the constant expression $e_i$, $i \in 1 .. n$. -The $i$th element of $a$ (at index $i - 1$) is $v_i$. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The value of a constant list literal -\code{\CONST?\,\,[$e_1, \ldots, e_n$]} -is defined as the value of the constant list literal -% For a constant list literal, it is never an error to have the \CONST, even if -% it was omitted above. So we remove the `?`, making the next line well-defined. -\code{\CONST\,\,<\DYNAMIC>[$e_1, \ldots, e_n$]}. - -\LMHash{}% -Let -$list_1 =$ \code{\CONST?\,\,<$V$>[$e_{11}, \ldots, e_{1n}$]} -and -$list_2 =$ \code{\CONST?\,\,<$U$>[$e_{21}, \ldots, e_{2n}$]} -be two constant list literals and -let the elements of $list_1$ and $list_2$ evaluate to -$o_{11}, \ldots, o_{1n}$ and $o_{21}, \ldots, o_{2n}$ respectively. -If{}f \code{identical($o_{1i}$, $o_{2i}$)} for $i \in 1 .. n$ and $V == U$ -then \code{identical($list_1$, $list_2$)}. - -\commentary{% -In other words, constant list literals are canonicalized.% -} - -\LMHash{}% -A run-time list literal -\code{<$E$>[$e_1, \ldots, e_n$]} -is evaluated as follows: -\begin{itemize} -\item - First, the expressions $e_1, \ldots, e_n$ are evaluated - in order they appear in the program, - producing objects $o_1, \ldots, o_n$. -\item - A fresh instance (\ref{generativeConstructors}) $a$, of size $n$, - whose class implements the built-in class \code{List<$E$>} - is allocated. -\item - The operator \lit{[]=} is invoked on $a$ with - first argument $i$ and second argument - $o_{i+1}, 0 \le i < n$. -\item - The result of the evaluation is $a$. -\end{itemize} - -\LMHash{}% -The objects created by list literals do not override -the \lit{==} operator inherited from the \code{Object} class. - -\commentary{ -Note that this document does not specify an order -in which the elements are set. -This allows for parallel assignments into the list -if an implementation so desires. -The order can only be observed as follows (and may not be relied upon): -if element $i$ is not a subtype of the element type of the list, -a dynamic type error will occur when $a[i]$ is assigned $o_{i-1}$. -} - -\LMHash{}% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -A run-time list literal -\code{[$e_1, \ldots, e_n$]} -is evaluated as -\code{<\DYNAMIC>[$e_1, \ldots, e_n$]}. - -\commentary{ -There is no restriction precluding nesting of list literals. -It follows from the rules above that -\code{{}>[[1, 2, 3], [4, 5, 6]]} -is a list with type parameter \code{List}, -containing two lists with type parameter \code{int}. -} - -\LMHash{}% -The static type of a list literal of the form -\code{\CONST\,\,<$E$>[$e_1, \ldots, e_n$]} -or the form -\code{<$E$>[$e_1, \ldots, e_n$]} -is \code{List<$E$>}. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The static type of a list literal of the form -\code{\CONST\,\,[$e_1, \ldots, e_n$]} -or the form -\code{[$e_1, \ldots, e_n$]} -is \code{List<\DYNAMIC>}. - - -\subsection{Maps} -\LMLabel{maps} - -\LMHash{}% -A \IndexCustom{map literal}{literal!map} denotes a map object. - -\begin{grammar} - ::= \CONST{}? ? - \gnewline{} `{' (`,' )* `,'? `}' - - ::= `:' - - ::= \CONST{}? ? `{' `}' -\end{grammar} - -\LMHash{}% -A \synt{setOrMapLiteral} $e$ is either a set literal (\ref {sets}) or a map literal, -determined by the type parameters or static context type. -If $e$ has exactly one type argument, then it is a set literal. -If $e$ has two type arguments, then it is a map literal. -If $e$ has three or more type arguments, it is a compile-time error. -If $e$ has \emph{no} type arguments, -then let $S$ be the static context type of the literal. -If $\futureOrBase{S}$ (\ref{typeFutureOr}) is a subtype of \code{Iterable} -and $\futureOrBase{S}$ is not a subtype of \code{Map}, -then $e$ is set literal, -and otherwise it is a map literal. -A map literal derived from \synt{setOrMapLiteral} -is treated the same way as one derived from \synt{mapLiteral}, -as described below. - -\LMHash{}% -A map literal consists of zero or more entries. -Each entry has a \Index{key} and a \Index{value}. -Each key and each value is denoted by an expression. -It is a compile-time error if a map literal has one type argument, -or more than two type arguments. - -\LMHash{}% -If a map literal $\ell$ begins with the reserved word \CONST{}, -or if $\ell$ occurs in a constant context -(\ref{constantContexts}), -it is a -\IndexCustom{constant map literal}{literal!map!constant} -which is a constant expression -(\ref{constants}) -and therefore evaluated at compile time. -Otherwise, it is a -\IndexCustom{run-time map literal}{literal!map!run-time} -and it is evaluated at run time. -Only run-time map literals can be mutated after they are created. -% This error can occur because being constant is a dynamic property, here. -Attempting to mutate a constant map literal will result in a dynamic error. - -\commentary{% -% The following is true either directly or indirectly: There is a \CONST{} -% modifier on the literal map, or we use the "immediate subexpression" rule -% about constant contexts. -Note that the key and value expressions of a constant list literal -occur in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly.% -} - -\LMHash{}% -It is a compile-time error if -either a key or a value of an entry in a constant map literal -is not a constant expression. -It is a compile-time error if -the operator \lit{==} of the key of an entry in a constant map literal -is not primitive -(\ref{theOperatorEqualsEquals}). -It is a compile-time error if a type argument of a constant map literal -is not a constant type expression -(\ref{constants}). - -\LMHash{}% -The value of a constant map literal -\code{\CONST?\,\,<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}} -is an object $m$ whose class implements the built-in class -\code{Map<$K, V$>}. -The entries of $m$ are $u_i:v_i, i \in 1 .. n$, -where $u_i$ is the value of the compile-time expression $k_i$, -and $v_i$ is the value of the compile-time expression $e_i$. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The value of a constant map literal -\code{\CONST?\,\,\{$k_1:e_1, \ldots, k_n:e_n$\}} -is defined as the value of the constant map literal -% For a constant map literal, it is never an error to have the \CONST, even if -% it was omitted above. So we remove the `?`, making the next line well-defined. -\code{\CONST\,\,<\DYNAMIC, \DYNAMIC>\{$k_1:e_1, \ldots, k_n:e_n$\}}. - -\LMHash{}% -Let $map_1$ be a constant map literal of the form -\code{\CONST?\,\,<$K, V$>\{$k_{11}:e_{11}, \ldots, k_{1n}:e_{1n}$\}} -and $map_2$ a constant map literal of the form -\code{\CONST?\,\,<$J, U$>\{$k_{21}:e_{21}, \ldots, k_{2n}:e_{2n}$\}}. -Let the keys of $map_1$ and $map_2$ evaluate to -$s_{11}, \ldots, s_{1n}$ and $s_{21}, \ldots, s_{2n}$, respectively, -and let the elements of $map_1$ and $map_2$ evaluate to -$o_{11}, \ldots, o_{1n}$ and $o_{21}, \ldots, o_{2n}$, respectively. -If{}f -\code{identical($o_{1i}$, $o_{2i}$)} and -\code{identical($s_{1i}$, $s_{2i}$)} -for $i \in 1 .. n$, and $K == J, V == U$, then \code{identical($map_1$, $map_2$)}. - -\commentary{% -In other words, constant map literals are canonicalized.% -} - -\LMHash{}% -It is a compile-time error if two keys of a constant map literal are equal -according to their \lit{==} operator (\ref{equality}). - -\LMHash{}% -A run-time map literal -\code{<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}} -is evaluated as follows: -\begin{itemize} -\item - For each $i \in 1 .. n$ in numeric order, - first the expression $k_i$ is evaluated producing object $u_i$, - and then $e_i$ is evaluated producing object $o_i$. - This produces all the objects $u_1, o_1, \ldots, u_n, o_n$. -\item - A fresh instance (\ref{generativeConstructors}) $m$ - whose class implements the built-in class \code{Map<$K, V$>}, - is allocated. -\item - The operator \lit{[]=} is invoked on $m$ - with first argument $u_i$ and second argument $o_i$ - for each $i \in 1 .. n$. -\item - The result of the evaluation is $m$. -\end{itemize} - -\LMHash{}% -The objects created by map literals do not override -the \lit{==} operator inherited from the \code{Object} class. - -\LMHash{}% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -A run-time map literal -\code{\{$k_1:e_1, \ldots, k_n:e_n$\}} -is evaluated as - -\code{<\DYNAMIC, \DYNAMIC>\{$k_1:e_1, \ldots, k_n:e_n$\}}. - -\LMHash{}% -A map literal is ordered: -iterating over the keys and/or values of the maps -always happens in the order the keys appeared in the source code. - -\commentary{ -Of course, if a key repeats, the order is defined by first occurrence, -but the value is defined by the last. -} - -\LMHash{}% -The static type of a map literal of the form -\code{\CONST{} <$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}} -or the form -\code{<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}} -is -\code{Map<$K, V$>}. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The static type of a map literal of the form -\code{\CONST{} \{$k_1:e_1, \ldots, k_n:e_n$\}} -or the form -\code{\{$k_1:e_1, \ldots, k_n:e_n$\}} is -\code{Map<\DYNAMIC, \DYNAMIC>}. - - -\subsection{Sets} -\LMLabel{sets} - -\LMHash{}% -A \IndexCustom{set literal}{literal!set} denotes a set object. - -\begin{grammar} - ::= \CONST{}? ? - \gnewline{} `{' (`,' )* `,'? `\}' -\end{grammar} - -\LMHash{}% -A \synt{setOrMapLiteral} is either a set literal or a map literal -(\ref{maps}). -A set literal derived from \synt{setOrMapLiteral} -is treated the same way as one derived from \synt{setLiteral}, -as described below. - -\LMHash{}% -A set literal consists of zero or more element expressions. -It is a compile-time error if a set literal has more than one type argument. - -\rationale{% -A set literal with no type argument is always converted to a literal -with a type argument by type inference (\ref{overview}), so the following -section only address the behavior of literals with type arguments.% -} - -\LMHash{}% -If a set literal $\ell$ begins with the reserved word \CONST{} -or $\ell$ occurs in a constant context -(\ref{constantContexts}), -it is a -\IndexCustom{constant set literal}{literal!set!constant} -which is a constant expression -(\ref{constants}) -and therefore evaluated at compile time. -Otherwise, it is a -\IndexCustom{run-time set literal}{literal!set!run-time} -and it is evaluated at run time. -Only run-time set literals can be mutated after they are created. -% This error can occur because being constant is a dynamic property, here. -Attempting to mutate a constant set literal will result in a dynamic error. - -\commentary{% -% The following is true either directly or indirectly: There is a \CONST{} -% modifier on the literal set, or we use the "immediate subexpression" rule -% about constant contexts. -Note that the element expressions of a constant set literal -occur in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly.% -} - -\LMHash{}% -It is a compile-time error if an element expression in a constant set literal -is not a constant expression. -It is a compile-time error if -the operator \lit{==} of an element expression in a constant map literal -is not primitive -(\ref{theOperatorEqualsEquals}). -It is a compile-time error if the type argument of a constant set literal -is not a constant type expression -(\ref{constants}). -It is a compile-time error if two elements of a constant set literal are equal -according to their \lit{==} operator -(\ref{equality}). - -\LMHash{}% -The value of a constant set literal -\code{\CONST?\,\,<$E$>\{$e_1, \ldots, e_n$\}} -is an object $s$ whose class implements the built-in class -\code{Set<$E$>}. -The elements of $m$ are $v_i, i \in 1 .. n$, -where $v_i$ is the value of the constant expression $e_i$. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The value of a constant set literal -\code{\CONST?\,\,\{$e_1, \ldots, e_n$\}} -is defined as the value of the constant set literal -% For a constant set literal, it is never an error to have the \CONST, even if -% it was omitted above. So we remove the `?`, making the next line well-defined. -\code{\CONST\,\,<\DYNAMIC>\{$e_1, \ldots, e_n$\}}. - -\LMHash{}% -Let $set_1$ be a constant set literal with type argument $E$ -and element expressions, in source order, $e_{11}, \ldots, e_{1n}$ evaluating -to values $v_{11}, \ldots, v_{1n}$. -Let $set_2$ be a constant set literal with type argument $F$ -and element expressions, in source order, $e_{21}, \ldots, e_{2n}$ evaluating -to values $v_{21}, \ldots, v_{2n}$. -If{}f \code{identical($v_{1i}$, $v_{2i}$)} -for $i \in 1 .. n$, and $E$ and $F$ is the same type, -then \code{identical($set_1$, $set_2$)}. - -\commentary{% -In other words, constant set literals are canonicalized if they have -the same type and the same values in the same order. -Two constant set literals are never identical -if they have a different number of elements.% -} - -\LMHash{}% -A run-time set literal with element expressions $e_1, \ldots, e_n$ -(in source order) and with type argument $E$ -is evaluated as follows: -\begin{itemize} -\item -For each $i \in 1 .. n$ in numeric order, -the expression $e_i$ is evaluated producing object $v_i$. -\item A fresh object (\ref{generativeConstructors}) $s$ -implementing the built-in class \code{Set<$E$>}, is created. -\item The set $s$ is made to have the values $v_1, \ldots{} , v_n$ as elements, -iterated in numerical order. -\item -The result of the evaluation is $s$. -\end{itemize} - -\LMHash{}% -The objects created by set literals do not override -the \lit{==} operator inherited from the \code{Object} class. - -\LMHash{}% -A set literal is ordered: iterating over the elements of the sets -always happens in the order the elements first appeared in the source code. - -\commentary{ -If a value repeats, the order is defined by first occurrence, but the value is defined by the last. -} - -\LMHash{}% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -A run-time set literal -\code{\{$e_1, \ldots, e_n$\}} -is evaluated as -\code{<\DYNAMIC>\{$e_1, \ldots, e_n$\}}. - -\LMHash{}% -The static type of a set literal of the form -\code{\CONST\,\,<$E$>\{$e_1, \ldots, e_n$\}} -or the form -\code{<$E$>\{$e_1, \ldots, e_n$\}} -is -\code{Set<$E$>}. -% -%% TODO(eernst): If inference is specified to provide all type arguments, -%% we should delete the following. -The static type of a list literal of the form -\code{\CONST\,\,\{$e_1, \ldots, e_n$\}} -or the form -\code{\{$e_1, \ldots, e_n$\}} -is \code{Set<\DYNAMIC>}. - - -\subsection{Throw} -\LMLabel{throw} - -\LMHash{}% -The \Index{throw expression} is used to throw an exception. - -\begin{grammar} - ::= \THROW{} - - ::= \THROW{} -\end{grammar} - -\LMHash{}% -Evaluation of a throw expression of the form \code{\THROW{} $e$;} proceeds as follows: - -\LMHash{}% -The expression $e$ is evaluated to an object $v$ -(\ref{expressionEvaluation}). - -\commentary{ -There is no requirement that the expression $e$ must evaluate to any special kind of object. -} - -\LMHash{}% -If $v$ is the null object (\ref{null}), then a \code{NullThrownError} is thrown. -Otherwise let $t$ be a stack trace corresponding to the current execution state, -and the \THROW{} statement throws with $v$ as exception object -and $t$ as stack trace (\ref{expressionEvaluation}). - -\LMHash{}% -If $v$ is an instance of class \code{Error} or a subclass thereof, -and it is the first time that \code{Error} object is thrown, -the stack trace $t$ is stored on $v$ so that it will be returned -by the $v$'s \code{stackTrace} getter - -\commentary{ -If the same \code{Error} object is thrown more than once, its \code{stackTrace} getter will return the stack trace from the \emph{first} time it was thrown. -} - -\LMHash{}% -The static type of a throw expression is $\bot$. - - -\subsection{Function Expressions} -\LMLabel{functionExpressions} - -\LMHash{}% -A \IndexCustom{function literal}{literal!function} -is an anonymous declaration and an expression -that encapsulates an executable unit of code. - -\begin{grammar} - ::= -\end{grammar} - -\LMHash{}% -The grammar does not allow a function literal to declare a return type, -but it is possible for a function literal to have a -\IndexCustom{declared return type}{literal!function!declared return type}, -because it can be obtained by means of type inference. -Such a return type is included -when we refer to the declared return type of a function. - -\commentary{% -Type inference will be specified in a future version of this document. -Currently we consider type inference to be a phase that has completed, -and this document specifies the meaning of Dart programs -where inferred types have already been added. -} - -\LMHash{}% -We define the auxiliary function -\IndexCustom{\flatten{T}}{flatten(t)@\emph{flatten}$(T)$}, -which is used below and in other sections, as follows: - -\begin{itemize} -\item If $T$ is \code{FutureOr<$S$>} for some $S$ then $\flatten{T} = S$. - -\item Otherwise if -\code{$T <:$ Future} -then let $S$ be a type such that -\code{$T <:$ Future<$S$>} -and for all $R$, if -\code{$T <:$ Future<$R$>} -then $S <: R$. - -\rationale{ -This ensures that -\code{Future<$S$>} -is the most specific generic instantiation of \code{Future} that is a supertype of $T$. -%% TODO[class-interfaces]: When we have finished the specification of class -%% interface computations we may have the following property, but it is not -%% true at this point. Adjust the following by then! -Note that $S$ is well-defined because of the requirements on superinterfaces. -} - -Then $\flatten{T} = S$. - -\item In any other circumstance, $\flatten{T} = T$. -\end{itemize} - -\LMHash{}% -\Case{Positional, arrow} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) => $e$} - -\noindent -is -\FunctionTypePositionalStd{T_0}, - -\noindent -%% TODO[inference]: The static type of the function literal may come from context. -where $T_0$ is the static type of $e$. -\EndCase - -\LMHash{}% -\Case{Positional, arrow, future} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) \ASYNC{} => $e$} - -\noindent -is -\FunctionTypePositionalStdCr{\code{Future<\flatten{T_0}>}}, - -\noindent -where $T_0$ is the static type of $e$. -\EndCase - -\LMHash{}% -\Case{Named, arrow} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$\}) => $e$} - -\noindent -is -\FunctionTypeNamedStd{T_0}, - -\noindent -where $T_0$ is the static type of $e$. -\EndCase - -\LMHash{}% -\Case{Named, arrow, future} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$\}) \ASYNC{} => $e$} - -\noindent -is -\FunctionTypeNamedStdCr{\code{Future<\flatten{T_0}>}}, - -\noindent -where $T_0$ is the static type of $e$. -\EndCase - -\LMHash{}% -\Case{Positional, block} -The static type of a function literal of the form - -\noindent -\code{<\TypeParameters{X}{B}{S}>} - -\noindent -\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$]) \{ $s$ \}} - -\noindent -is -\FunctionTypePositionalStdCr{\DYNAMIC} -\EndCase - -\LMHash{}% -\Case{Positional, block, future} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) \ASYNC{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypePositionalStdCr{\code{Future}}. -\EndCase - -\LMHash{}% -\Case{Positional, block, stream} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) \ASYNC*{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypePositionalStdCr{\code{Stream}}. -\EndCase - -\LMHash{}% -\Case{Positional, block, iterable} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) \SYNC*{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypePositionalStdCr{\code{Iterable}}. -\EndCase - -\LMHash{}% -\Case{Named, block} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$]) \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypePositionalStdCr{\DYNAMIC}. -\EndCase - -\LMHash{}% -\Case{Named, block, future} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$\}) \ASYNC{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypeNamedStdCr{\code{Future}}. -\EndCase - -\LMHash{}% -\Case{Named, block, stream} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$\}) \ASYNC*{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypeNamedStdCr{\code{Stream}}. -\EndCase - -\LMHash{}% -\Case{Named, block, iterable} -The static type of a function literal of the form - -\noindent -\code{<\TypeParametersStd>} - -\noindent -\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$\}) \SYNC*{} \{ $s$ \}} - -\noindent -is -%% TODO(eernst): Adjust to take type inference into account. -\FunctionTypeNamedStdCr{\code{Iterable}}. -\EndCase - -\LMHash{}% -In all of the above cases, -the type argument lists are omitted when $m=0$, -and whenever $T_i$ is not specified, $i \in 1 .. n+k$, -it is considered to have been specified as \DYNAMIC{}. - -\LMHash{}% -Evaluation of a function literal yields a function object $o$. - -\commentary{ -The run-time type of $o$ is specified based on -the static type $T$ of the function literal -and the binding of type variables occurring in $T$ -at the occasion where the evaluation occurred -(\ref{typeOfAFunction}). -} - - -\subsection{This} -\LMLabel{this} - -\LMHash{}% -The reserved word \THIS{} denotes the target of the current instance member invocation. - -\begin{grammar} - ::= \THIS{} -\end{grammar} - -\LMHash{}% -The static type of \THIS{} is the interface of the immediately enclosing class. - -\commentary{ -We do not support self-types at this point. -} - -\LMHash{}% -It is a compile-time error if \THIS{} appears, implicitly or explicitly, in a top-level function or variable initializer, in a factory constructor, or in a static method or variable initializer, or in the initializer of an instance variable. - - -\subsection{Instance Creation} -\LMLabel{instanceCreation} - -\LMHash{}% -Instance creation expressions generally produce instances -and invoke constructors to initialize them. - -\commentary{ -The exception is that -a factory constructor invocation works like a regular function call. -It may of course evaluate an instance creation expression and thus -produce a fresh instance, -but no fresh instances are created as a direct consequence of -the factory constructor invocation. -} - -%It is a compile-time error if any of the type arguments to a constructor of a generic type invoked by a new expression or a constant object expression do not denote types in the enclosing lexical scope. - -%It is a compile-time error if a constructor of a non-generic type invoked by a new expression or a constant object expression is passed any type arguments. It is a compile-time error if a constructor of a generic type with $n$ type parameters invoked by a new expression or a constant object expression is passed $m$ type arguments where $m \ne n$, or if any of its type arguments is misconstructed (\ref{parameterizedTypes}). - -\LMHash{}% -It is a compile-time error if -the type $T$ in an instance creation expression of one of the forms - -\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, - -\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, - -\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, - -\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - -\noindent -is an enumerated type (\ref{enums}). - - -\subsubsection{New} -\LMLabel{new} - -\LMHash{}% -The \Index{new expression} invokes a constructor (\ref{constructors}). - -\begin{grammar} - ::= \NEW{} (`.' )? -\end{grammar} - -\LMHash{}% -Let $e$ be a new expression of the form - -\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -or the form - -\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. - -\LMHash{}% -It is a compile-time error if $T$ is not -a class or a parameterized type accessible in the current scope, -or if $T$ is a parameterized type which is not a class. -\commentary{ -For instance, \code{\NEW{} F()} is an error if \code{F} is a type alias -that does not denote a class. -} - -\LMHash{}% -If $T$ is a parameterized type (\ref{parameterizedTypes}) -\code{$S$<$U_1, \ldots,\ U_m$>}, -let $R$ be the generic class $S$, -and let -\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_p\ \EXTENDS\ B_p$} -be the formal type parameters of $S$. -If $T$ is not a parameterized type, let $R$ be $T$. - -\begin{itemize} -\item - If $e$ is of the form - \code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - it is a compile-time error if \code{$R$.\id} is not the name of - a constructor declared by $R$, or \id{} is not accessible. -\item - If $e$ is of the form - \code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - it is a compile-time error if $R$ is not the name of - a constructor declared by $R$. -\end{itemize} - -\LMHash{}% -Let $q$ be the above-mentioned constructor named \code{$R$.\id} or $R$. - -\LMHash{}% -It is a compile-time error if $R$ is abstract -and $q$ is not a factory constructor. -It is a compile-time error if $R$ is a non-generic class -and $T$ is a parameterized type. -%% We assume that inference has taken place, so actual type arguments -%% are always given explicitly. -It is a compile-time error if $R$ is a generic class -and $T$ is not a parameterized type. -It is a compile-time error if $R$ is a generic class, -$T$ is a parameterized type, and $m \not= p$. -\commentary{That is, the number of type arguments is incorrect.} -It is a compile-time error if $R$ is a generic class, -$T$ is a parameterized type, -and $T$ is not regular-bounded -(\ref{superBoundedTypes}). - -\LMHash{}% -If $q$ is a redirecting factory constructor, -it is a compile-time error if $q$ in some number of -redirecting factory redirections redirects to itself. -\commentary{ -It is possible and allowed for a redirecting factory $q'$ -to enter an infinite loop, e.g., -because $q'$ redirects to a non-redirecting factory constructor -$q''$ whose body uses $q'$ in an instance creation expression. -Only loops that consist exclusively of redirecting factory redirections -are detected at compile time. -} - -\LMHash{}% -Let $S_i$ be the static type of -the formal parameter of the constructor \code{$R$.\id} (respectively $R$) -corresponding to the actual argument $a_i$, $i \in 1 .. n+k$. -It is a compile-time error if the static type of -$a_i, i \in 1 .. n + k$ -is not assignable to $[U_1/X_1, \ldots, U_m/X_m]S_i$. -\commentary{ -The non-generic case is covered with $m = 0$. -} - -\LMHash{}% -The static type of $e$ is $T$. - -\LMHash{}% -Evaluation of $e$ proceeds as follows: - -\LMHash{}% -First, the argument part - -\code{<$U_1, \ldots,\ U_m$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - -\noindent -is evaluated, yielding the evaluated actual argument part - -\code{<$u_1, \ldots,\ u_m$>($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1},\ \ldots,\ x_{n+k}$: $o_{n+k}$)}. - -\noindent -\commentary{Note that the non-generic case is covered by letting $m = 0$.} -% This error can occur due to an implicit cast. -If for any -$j \in 1 .. n + k$ -the run-time type of $o_j$ is not a subtype of -$[u_1/X_1, \ldots, u_m/X_m]S_j$, -a dynamic type error occurs. - -\LMHash{}% -\Case{Non-loaded deferred constructors} -% This error can occur because being-loaded is a dynamic property. -If $T$ is a deferred type with prefix $p$, -then if $p$ has not been successfully loaded, -a dynamic error occurs. -\EndCase - -\LMHash{}% -\Case{Generative constructors} -When $q$ is a generative constructor -(\ref{generativeConstructors}) -evaluation proceeds to allocate a fresh instance -(\ref{generativeConstructors}), $i$, of class $T$. -% We provide the type arguments as part of the class of the instance -% because $T$ includes the type arguments; but we also provide them -% as a binding accessible to the constructor: Otherwise we couldn't -% access the type parameters in the initializing expressions of the -% initializer list where there is no access to \THIS{}. -Then $q$ is executed to initialize $i$ with respect to -the bindings that resulted from the evaluation of the argument list, and, -if $R$ is a generic class, -with its type parameters bound to $u_1, \ldots, u_m$. - -\LMHash{}% -If execution of $q$ completes normally (\ref{statementCompletion}), $e$ evaluates to $i$. -Otherwise execution of $q$ throws an exception object $x$ and stack trace $t$, -and then evaluation of $e$ also throws exception object $x$ and stack trace $t$ -(\ref{expressionEvaluation}). -\EndCase - -\LMHash{}% -\Case{Redirecting factory constructors} -When $q$ is a redirecting factory constructor -(\ref{factories}) -of the form \code{\CONST{}? $T$($p_1, \ldots,\ p_{n+k}$) = $c$;} or -of the form \code{\CONST{}? $T$.\id($p_1, \ldots,\ p_{n+k}$) = $c$;} -where \code{\CONST{}?} indicates that \CONST{} may be present or absent, -the remaining evaluation of $e$ is equivalent to -evaluating -\code{\NEW{} $c$($v_1, \ldots,\ v_n,\ x_{n+1}$: $v_{n+1}, \ldots,\ x_{n+k}$: $v_{n+k}$)} -in an environment where -$v_j$ is a fresh variable bound to $o_j$ for $j \in 1 .. n + k$, and -$X_j$ is bound to $u_j$ for $j \in 1 .. m$. -\commentary{% -We need access to the type variables because $c$ may contain them.% -} -\EndCase - -\LMHash{}% -\Case{Non-redirecting factory constructors} -When $q$ is a non-redirecting factory constructor, -the body of $q$ is executed with respect to -the bindings that resulted from the evaluation of the argument list, -and with the type parameters, if any, of $q$ bound to -the actual type arguments $u_1, \ldots, u_m$. -If this execution returns a value (\ref{statementCompletion}), -then $e$ evaluates to the returned value. -Otherwise, if the execution completes normally or returns with no value, -then $e$ evaluates to the null object (\ref{null}). -Otherwise the execution throws an exception $x$ and stack trace $t$, -and then evaluation of $e$ also throws $x$ and $t$ -(\ref{expressionEvaluation}). - -\rationale{ -A factory constructor can be declared in an abstract class and used safely, -as it will either produce a valid instance or throw. -} -\EndCase - - -\subsubsection{Const} -\LMLabel{const} - -\LMHash{}% -A \Index{constant object expression} invokes a constant constructor -(\ref{constantConstructors}). - -\begin{grammar} - ::= \CONST{} (`.' )? -\end{grammar} - -\LMHash{}% -Let $e$ be a constant object expression of the form - -\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -or the form - -\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. - -\LMHash{}% -It is a compile-time error if $T$ is not -a class or a parameterized type accessible in the current scope, -or if $T$ is a parameterized type which is not a class. -It is a compile-time error if $T$ is a deferred type -(\ref{staticTypes}). -\commentary{ -In particular, $T$ must not be a type variable. -} - -\LMHash{}% -It is a compile-time error if $a_i$ is not a constant expression -for some $i \in 1 .. n + k$. - -\LMHash{}% -If $T$ is a parameterized type (\ref{parameterizedTypes}) -\code{$S$<$U_1, \ldots,\ U_m$>}, -let $R$ be the generic class $S$, -and let -\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_p\ \EXTENDS\ B_p$} -be the formal type parameters of $S$. -If $T$ is not a parameterized type, let $R$ be $T$. - -\LMHash{}% -If $T$ is a parameterized type, -it is a compile-time error if $U_j$ is not a constant type expression for any -$j \in 1 .. m$. - -\begin{itemize} -\item - If $e$ is of the form - \code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - it is a compile-time error if \code{$R$.\id} is not the name of - a constant constructor declared by $R$, or \id{} is not accessible. -\item - If $e$ is of the form - \code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} - it is a compile-time error if $R$ is not the name of - a constant constructor declared by $R$. -\end{itemize} - -\LMHash{}% -Let $q$ be the above-mentioned constant constructor named \code{$R$.\id} or $R$. - -%% TODO(eernst): These errors are the same as with `new`. Can we avoid -%% stating them twice? We'd need to refer to an awkwardly shaped portion -%% of text in the previous subsection, or just loosely say "exactly the -%% same errors".. -\LMHash{}% -It is a compile-time error if $R$ is abstract -and $q$ is not a factory constructor. -It is a compile-time error if $R$ is a non-generic class -and $T$ is a parameterized type. -%% We assume that inference has taken place, so actual type arguments -%% are always given explicitly. -It is a compile-time error if $R$ is a generic class -and $T$ is not a parameterized type. -It is a compile-time error if $R$ is a generic class, -$T$ is a parameterized type, and $m \not= p$. -\commentary{That is, the number of type arguments is incorrect.} -It is a compile-time error if $R$ is a generic class, -$T$ is a parameterized type, -and $T$ is not regular-bounded -(\ref{superBoundedTypes}). - -\LMHash{}% -Let $S_i$ be the static type of -the formal parameter of the constructor \code{$R$.\id} (respectively $R$) -corresponding to the actual argument $a_i$, $i \in 1 .. n+k$. -It is a compile-time error if the static type of -$a_i, i \in 1 .. n + k$ -is not assignable to $[U_1/X_1, \ldots, U_m/X_m]S_i$. -\commentary{ -The non-generic case is covered with $m = 0$. -} - -\LMHash{}% -The static type of $e$ is $T$. - -\LMHash{}% -Evaluation of $e$ proceeds as follows: - -\LMHash{}% -If $e$ is of the form -\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} -let $i$ be the value of the expression $e'$: -\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. -\commentary{ -Let $o$ be the result of an evaluation of $e'$, -at some point in time of some execution of the program -in the library $L$ where $e$ occurs. -The result of an evaluation of $e'$ in $L$ -at some other time and/or in some other execution will -yield a result $o'$, such that $o'$ would be replaced by $o$ -by canonicalization as described below. -This means that the value is well-defined. -} - -\LMHash{}% -If $e$ is of the form -\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, -let $i$ be the value of -\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}. -\commentary{ -Which is well-defined for the same reason. -} - -\LMHash{}% -\begin{itemize} -\item If during execution of the program, - a constant object expression has already evaluated to - an instance $j$ of class $R$ with type arguments $U_i, 1 \le i \le m$, then: -\begin{itemize} -\item For each instance variable $f$ of $i$, - let $v_{if}$ be the value of the instance variable $f$ in $i$, and - let $v_{jf}$ be the value of the instance variable $f$ in $j$. - If \code{identical($v_{if}$, $v_{jf}$)} for all instance variables $f$ in $i$ - then the value of $e$ is $j$, otherwise the value of $e$ is $i$. -\end{itemize} -\item Otherwise the value of $e$ is $i$. -\end{itemize} - -\commentary{ -In other words, constant objects are canonicalized. -In order to determine if an object is actually new, one has to compute it; -then it can be compared to any cached instances. -If an equivalent object exists in the cache, -we throw away the newly created object and use the cached one. -Objects are equivalent if -they have identical type arguments and identical instance variables. -Since the constructor cannot induce any side effects, -the execution of the constructor is unobservable. -The constructor need only be executed once per call site, at compile time. -} - -\LMHash{}% -It is a compile-time error if evaluation of a constant object -results in an uncaught exception being thrown. - -\commentary{ -To see how such situations might arise, consider the following examples: -} - -%% TODO(eernst): Delete some \CONST{} when integrating implicit-creation.md -\begin{dartCode} -\CLASS{} A \{ - \FINAL{} x; - \CONST{} A(p): x = p * 10; -\} -\\ -\CLASS{} IntPair \{ - \CONST{} IntPair(\THIS{}.x, \THIS{}.y); - \FINAL{} int x; - \FINAL{} int y; - \OPERATOR *(v) => \NEW{} IntPair(x*v, y*v); -\} -\\ -\CONST a1 = \CONST{} A(true); // \comment{compile-time error} -\CONST a2 = \CONST{} A(5); // \comment{legal} -\CONST a3 = \CONST{} A(\CONST{} IntPair(1,2)); // \comment{compile-time error} -\end{dartCode} - -\commentary{ -Due to the rules governing constant constructors, -evaluating the constructor \code{A()} -with the argument \code{"x"} or the argument \code{\CONST{} IntPair(1, 2)} -would cause it to throw an exception, resulting in a compile-time error. -In the latter case, the error is caused by the fact that -\code{\OPERATOR{} *} can only be used with a few ``well-known'' types, -which is required in order to avoid running arbitrary code during -the evaluation of constant expressions. -} - - -\subsection{Spawning an Isolate} -\LMLabel{spawningAnIsolate} - -\LMHash{}% -Spawning an isolate is accomplished via what is syntactically an ordinary library call, invoking one of the functions \code{spawnUri()} or \code{spawn()} defined in the \code{dart:isolate} library. -However, such calls have the semantic effect of creating a new isolate with its own memory and thread of control. - -\LMHash{}% -An isolate's memory is finite, as is the space available to its thread's call stack. -% This error can occur because memory usage is a dynamic property. -It is possible for a running isolate to exhaust its memory or stack, -resulting in a dynamic error that cannot be effectively caught, -which will force the isolate to be suspended. - -\commentary{ -As discussed in section \ref{errorsAndWarnings}, the handling of a suspended isolate is the responsibility of the embedder. -} - - -\subsection{Function Invocation} -\LMLabel{functionInvocation} - -\LMHash{}% -Function invocation occurs in the following cases: -when a function expression (\ref{functionExpressions}) is invoked (\ref{functionExpressionInvocation}), -when a method (\ref{methodInvocation}), getter (\ref{topLevelGetterInvocation}, \ref{propertyExtraction}) or setter (\ref{assignment}) is invoked, -or when a constructor is invoked -(either via instance creation (\ref{instanceCreation}), constructor redirection (\ref{redirectingGenerativeConstructors}), or super initialization). -The various kinds of function invocation differ as to how the function to be invoked, $f$, is determined, as well as whether \THIS{} (\ref{this}) is bound. -Once $f$ has been determined, -formal type parameters of $f$ are bound to the corresponding actual type arguments, -and the formal parameters of $f$ are bound to corresponding actual arguments. -When the body of $f$ is executed it will be executed with the aforementioned bindings. - -\LMHash{}% -Executing a body of the form \code{=> $e$} is equivalent to executing a body of the form \code{\{ return $e$; \}}. -Execution a body of the form \code{\ASYNC{} => $e$} is equivalent to executing a body of the form \code{\ASYNC{} \{ return $e$; \}}. - -\LMHash{}% -If $f$ is synchronous and is not a generator (\ref{functions}) then execution of the body of $f$ begins immediately. -If the execution of the body of $f$ returns a value, $v$, (\ref{statementCompletion}), the invocation evaluates to $v$. -If the execution completes normally or it returns without a value, the invocation evaluates to the null object (\ref{null}). -If the execution throws an exception object and stack trace, -the invocation throws the same exception object and stack trace -(\ref{expressionEvaluation}). - -\commentary{% -A complete function body can never break or continue (\ref{statementCompletion}) -because a \BREAK{} or \CONTINUE{} statement must always occur inside -the statement that is the target of the \BREAK{} or \CONTINUE{}. -This means that a function body can only either complete normally, throw, or return. -Completing normally or returning without a value is treated -the same as returning the null object (\ref{null}), -so the result of executing a function body can always be used as -the result of evaluating an expression, -either by evaluating to an object, or by the evaluation throwing.% -} - -\LMHash{}% -If $f$ is marked \code{\SYNC*} (\ref{functions}), -then a fresh instance (\ref{generativeConstructors}) $i$ -implementing \code{Iterable<$U$>} is immediately returned, -where $U$ is determined as follows: -Let $T$ be the actual return type of $f$ (\ref{actualTypeOfADeclaration}). -If $T$ is \code{Iterable<$S$>} for some type $S$, then $U$ is $S$, -otherwise $U$ is \code{Object}. - -\commentary{ -A Dart implementation will need to provide a specific implementation of \code{Iterable} that will be returned by \code{\SYNC*} methods. -A typical strategy would be to produce an instance of a subclass of class \code{IterableBase} defined in \code{dart:core}. -The only method that needs to be added by the Dart implementation in that case is \code{iterator}. -} - -\LMHash{}% -The iterable implementation must comply with the contract of \code{Iterable} and should not take any steps identified as exceptionally efficient in that contract. - -\commentary{ -The contract explicitly mentions a number of situations where certain iterables could be more efficient than normal. -For example, by precomputing their length. -Normal iterables must iterate over their elements to determine their length. -This is certainly true in the case of a synchronous generator, where each element is computed by a function. -It would not be acceptable to pre-compute the results of the generator and cache them, for example. -} - -\LMHash{}% -When iteration over the iterable is started, by getting an iterator $j$ from the iterable and calling \code{moveNext()}, execution of the body of $f$ will begin. -When execution of the body of $f$ completes (\ref{statementCompletion}), -\begin{itemize} -\item If it returns without a value or it completes normally (\ref{statementCompletion}), $j$ is positioned after its last element, so that its current value is the null object (\ref{null}) and the current call to \code{moveNext()} on $j$ returns false, as must all further calls. -\item If it throws an exception object $e$ and stack trace $t$ then the current value of $j$ is the null object (\ref{null}) and the current call to \code{moveNext()} throws $e$ and $t$ as well. -Further calls to \code{moveNext()} must return false. -\end{itemize} - -Each iterator starts a separate computation. -If the \code{\SYNC*} function is impure, the sequence of values yielded by each iterator may differ. - -\commentary{ -One can derive more than one iterator from a given iterable. -Note that operations on the iterable itself can create distinct iterators. -An example would be \code{length}. -It is conceivable that different iterators might yield sequences of different length. -The same care needs to be taken when writing \code{\SYNC*} functions as when -writing an \code{Iterator} class. -In particular, it should handle multiple simultaneous iterators gracefully. -If the iterator depends on external state that might change, it should check that the state is still valid after every yield (and maybe throw a \code{ConcurrentModificationError} if it isn't). -} - -\LMHash{}% -Each iterator runs with its own shallow copies of all local variables; in particular, each iterator has the same initial arguments, even if their bindings are modified by the function. -\commentary{ -Two executions of an iterator interact only via state outside the function. -} -% The alternative would be to cache the results of an iterator in the iterable, and check the cache at each \YIELD{}. This would have strange issues as well. The yielded value might differ from the expression in the yield. And it is a potential memory leak as the cache is kept alive by any iterator. - -\LMHash{}% -If $f$ is marked \ASYNC{} (\ref{functions}), -then a fresh instance (\ref{generativeConstructors}) $o$ is associated with the invocation, -where the dynamic type of $o$ implements \code{Future<$flatten(T)$>}, -and $T$ is the actual return type of $f$ (\ref{actualTypeOfADeclaration}). -Then the body of $f$ is executed until it either suspends or completes, at which point $o$ is returned. -\commentary{ -The body of $f$ may suspend during the evaluation of an \AWAIT{} expression or execution of an asynchronous \FOR{} loop. -} -The future $o$ is completed when execution of the body of $f$ completes (\ref{statementCompletion}). -If execution of the body returns a value, $o$ is completed with that value, -if it completes normally or returns without a value, -$o$ is completed with the null object (\ref{null}), -and if it throws an exception $e$ and stack trace $t$, -$o$ is completed with the error $e$ and stack trace $t$. -If execution of the body throws before the body suspends the first time, -completion of $o$ happens at some future time after the invocation has returned. -\rationale{ -The caller needs time to set up error handling for the returned future, -so the future is not completed with an error \emph{before} it has been returned. -} - -\LMHash{}% -If $f$ is marked \code{\ASYNC*} (\ref{functions}), -then a fresh instance (\ref{generativeConstructors}) $s$ -implementing \code{Stream<$U$>} is immediately returned, -where $U$ is determined as follows: -Let $T$ be the actual return type of $f$ (\ref{actualTypeOfADeclaration}). -If $T$ is \code{Stream<$S$>} for some type $S$, then $U$ is $S$, -otherwise $U$ is \code{Object}. -When $s$ is listened to, execution of the body of $f$ will begin. -When execution of the body of $f$ completes: -\begin{itemize} -\item If it completes normally or returns with no value (\ref{statementCompletion}), then if $s$ has been canceled then its cancellation future is completed with the null object (\ref{null}). -\item If it throws an exception object $e$ and stack trace $t$: - \begin{itemize} - \item If $s$ has been canceled then its cancellation future is completed with error $e$ and stack trace $t$. - \item otherwise the error $e$ and stack trace $t$ are emitted by $s$. - \end{itemize} -\item $s$ is closed. -\end{itemize} -\commentary{ -The body of an asynchronous generator function cannot break, continue or return a value (\ref{statementCompletion}). -The first two are only allowed in contexts that will handle the break or continue, and return statements with an expression are not allowed in generator functions. -} - -\rationale{ -When an asynchronous generator's stream has been canceled, cleanup will occur in the \FINALLY{} clauses (\ref{try}) inside the generator. -We choose to direct any exceptions that occur at this time to the cancellation future rather than have them be lost. -} - -%\LMHash{}% -%When a stream is canceled, the implementation must wait for the cancelation future returned by \code{cancell()} to complete before proceeding. - - -\subsubsection{Actual Argument Lists} -\LMLabel{actualArgumentLists} - -\LMHash{}% -Actual argument lists have the following syntax: - -\begin{grammar} - ::= `(' ( `,'?)? `)' - - ::= (`,' )* - \alt (`,' )* - - ::=