tldr: As part of Dart 2 release, we will be enabling --preview-dart-2 by default. This will cause some breakages due to stricter Dart type enforcement. The change is expected in master in the next few days, and will likely be propagated to our next beta channel build.
Some weeks back the Dart team announced Dart 2, and we offered steps to preview Dart 2 with Flutter. We are now ready to turn on --preview-dart-2 by default. If you have not already tested your Flutter apps and packages, please do so now to see if you are impacted.
Changes to Dart 2 type system include a compile-time component and a runtime component. We don’t anticipate any significant breakages from new compile-time errors introduced in Dart 2 because Flutter already opted into this part of Dart 2 by enabling strong mode in the analyzer. You may, however, see new runtime errors as we are now also enabling this part of Dart 2 semantics in VM.
Types of local variables, function literals and type arguments for method invocations and List/Map literals are inferred using strong mode type inference rules. For example, in Dart 2 this code that omits explicit variable types:
var x = 3; |
is the same as:
int x = 3; |
Underlined types are inferred by local type inference.
In rare cases type inference will lead to runtime type check failures where they didn’t occur before:
class A { // because variable v is inferred to have static type B, // and assigning a value of static type A to a variable of type B // is an implicit downcast. |
To fix this kind of issue, simply declare types of local variables explicitly:
A foo(bool f) { |
In Dart 1, the dynamic type was treated as a kind of wildcard type that could be used anywhere. For example:
a value of type List<dynamic> was assignable to List<String>
a function of type (int) → void was assignable to (dynamic) → void
void main() { |
The implications of this on Flutter are most visible around JSON processing and platform message channels:
import 'dart:convert'; |
A similar issue exists with Lists.
Use Map.cast, Map.retype, List.cast and List.retype to convert a List or Map into an appropriate type. Note that conversion is shallow and nested objects need to be converted separately.
import 'dart:convert'; |
Dart 2 has a sound type system with compile-time type checking (this has been available to Flutter developers for months). Soundness means that you can't encounter a value of the wrong type at runtime. To ensure this, runtime type checks are inserted by the compiler in potentially unsafe code. This can cause your code to throw a type error at runtime.
By default, in Dart 2 you can assign an object to any location whose static type is a supertype or a subtype of the static type of the object:
final Object a = “hello”; // throws: Type 'String' is not a subtype of type 'int' |
This is statically allowed, but at runtime, the assignment will be checked and will fail. The most common causes of these kinds of failures are incorrect uses of generics:
List<dynamic> makeList(x, y) => [x, y]; // throws: type 'List' is not a subtype of type 'List<int>' |
Even though the list being returned contains only integers, the list was created as a List<dynamic> (and nothing stops non-integers from being added to it later), and so the runtime check on the assignment to a will fail. Fixing these kinds of errors is usually best done by tracking down the place where the offending object was allocated, and arranging for it to allocated with the correct runtime type.
List<dynamic> getList(x, y) => <int>[x, y]; |
Generic methods can often help with this in the general case:
List<T> makeList<T>(T x, T y) => [x, y]; |
See this overview and this troubleshooting guide for more discussion, and feel free to follow up on mailing lists, chat rooms, or StackOverflow for help resolving issues.
In Dart 2 functions that are marked as async will start to run immediately instead of being delayed by one microtask.
If your code relies on the detailed timing aspects of asynchronous functions (which should be rare) you may be impacted; if not, you code will just run as-is, or slightly faster.
Please review the details in the previous announcement.
Type arguments of generic methods are reified in runtime
void pr<T>(T v) { |
Code that assumes that types are not preserved at runtime. Prior to this change, the code above would print dynamic 4 times.
Rewrite the code to not assume that types will be erased.
new and const may be omitted when calling a constructor
// Dart 1 |
The change is expected to land later this week in the Master channel, and will then be propagated to the various Flutter channels over the following days and weeks.
All the type changes listed above under the ‘Breaking changes’ heading have the potential to break your existing application or package. Our recommendation is to asap test your code with the preview flag:
Upgrade to flutter beta 1 or later
Run your app with the preview flag enabled on
Keep an eye out for typing issues printed to the console during compilation, and during execution, of the application
Resolve the issues as per the details at the top of this post
Dart 2 is an update to the Dart programming language that introduces a number of improvements to the Dart language, such as:
A complete run-time typing system (the primary content of the present post)
Optional new/const keyword when calling a constructor (e.g., change child: new Text('Hi') to child: Text('Hi'))
Various smaller language changes
The changes are now mature enough to land in Flutter.
We will send an update here when this change lands. Please send an email to flutter-dev@ for any issues or questions.
Thanks,
Leaf and Michael
--
You received this message because you are subscribed to the Google Groups "Flutter Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.