Author: eernst@.
Version: 0.2 (2017-08-30)
Status: Under implementation.
This document is an informal specification of the optional const feature. The feature adds support for omitting the reserved word const
in list and map literals and constant object expressions, in locations where const
is currently required.
This informal specification is built on a combined proposal which presents optional const and several other features.
In Dart without optional const, complex constant expressions often contain many occurrences of const
on list and map literals, and on constant object expressions. Subexpressions of constant expressions are themselves required to be constant expressions, and this means that const
on a nested list or map literal provides no extra information: It is a compile-time error if that const
is omitted. Similarly, it is a compile-time error if a nested constant object expression is modified to use new
rather than const
. In that situation it carries no extra information whether new
or const
is used, and it is even possible to omit the reserved word entirely. It is also required for certain other expressions to be constant, e.g., initializing expressions for constant variables.
In all these cases the presence of const
is required, and hence such a const
may be inferred by compilers and similar tools if it is omitted.
Developers reading the source code are likely to find it easy to understand that a required const
was omitted and is implied, because the reason for the requirement is visible in the enclosing syntax: The expression where const
is inferred is a subexpression of an expression with const
or it is used in another situation where a constant value is required, e.g., to initialize a constant variable.
In summary, tools do not need the required occurrences of const
, and they are also unimportant for developers. Conversely, omitting required occurrences of const
will sometimes make large expressions substantially more concise and readable, and also more convenient to write. Here is an example:
const myMap = const { "a": const [const C("able"), const C("apple"), const C("axis")], "b": const [const C("banana"), const C("bold"), const C("burglary")], };
Removing the required occurrences of const
yields the following:
const myMap = { "a": [C("able"), C("apple"), C("axis")], "b": [C("banana"), C("bold"), C("burglary")], };
This proposal specifies that these previously required occurrences of const
can be omitted, and will then be inferred.
For a more detailed discussion and motivation, please consult the combined proposal which covers optional const as well as several other proposals. That document was the starting point for this informal specification.
In order to support the optional const feature, the Dart grammar is modified as follows.
postfixExpression ::= assignableExpression postfixOperator | constructorInvocation | // NEW primary selector* constructorInvocation ::= // NEW typeName typeArguments '.' identifier arguments
The grammar only needs to be adjusted for one case, namely invocations of named constructors for generic classes. In this case we can derive expressions like const Foo<int>.bar()
, and the corresponding Foo<int>.bar()
is not derivable in the same situations where the variant with const
can be derived. In other words, we must add support for constructs like Foo<int>.bar()
as part of a postfixExpression
. For all other situations, the variant with const
becomes a construct which is already syntactically correct Dart when the const
is removed. For instance const C(42)
becomes C(42)
which is already allowed syntactically (syntactically, it could be a function invocation).
We specify a type directed source code transformation which eliminates the feature. The static analysis proceeds to work on the transformed program.
This means that the feature is “sugar”, but because of the need to refer to types it could be described as static semantic sugar rather than syntactic sugar. We do not specify the dynamic semantics for this feature, because the feature is eliminated in this transformation step.
We need to treat expressions differently in different locations, hence the following definition: An expression e is said to occur in a constant context,
Note that the default value of an optional formal parameter is not a constant context. This choice reserves some freedom to modify the semantics of default values.
An expression on one of the following forms must be modified to be or contain a constantObjectExpression
as described:
With a postfixExpression
e occurring in a constant context,
constructorInvocation
then replace e by const
e.typeIdentifier arguments
where typeIdentifier
denotes a class then replace e by const
e.identifier1 '.' identifier2 arguments
where identifier1
denotes a class and identifier2
is the name of a named constructor in that class, or identifier1
denotes a prefix for a library L and identifier2
denotes a class exported by L, replace e by const
e.identifier1 '.' typeIdentifier '.' identifier2 arguments
where identifier1
denotes a library prefix for a library L, typeIdentifier
denotes a class C exported by L, and identifier2
is the name of a named constructor in C, replace e by const
e.For a list literal e occurring in a constant context, replace e by const
e. For a map literal e occurring in a constant context, replace e by const
e.
In short, in these specific situations: “just add const
”. It is easy to verify that each of the replacements can be derived from constObjectExpression
, which can be derived from postfixExpression
via primary selector*
. Hence, the transformation preserves syntactic correctness.
The remaining static analysis proceeds to work on the transformed program.
It is possible that this transformation will create constObjectExpressions
which violate the constraints on constant object expressions, e.g., when const [[new A()]]
is transformed to const [const [new A()]]
where the inner list is an error that was created by the transformation (so the error was moved from the outer to the inner list). It is recommended that the error messages emitted by tools in response to such violations include information about the transformation.
There is no dynamic semantics to specify for this feature because it is eliminated by code transformation.
0.2 (2017-08-30) Updated the document to specify the previously missing transformations for composite literals (lists and maps), and to specify a no-magic approach (where no const
is introduced except when forced by the syntactic context).
0.1 (2017-08-10) Stand-alone informal specification for optional const created, using version 0.8 of the combined proposal optional-new-const.md as the starting point.