Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dart 3 Language Features: A New Era of Reliabil...

Dart 3 Language Features: A New Era of Reliability and Productivity

Dart 3 is the latest version of the Dart programming language, and it introduces a number of new features that make it more reliable and productive. These features include sound null safety, records, patterns, abstract data types, and class modifiers.

Sound null safety is one of the most important new features in Dart 3. It eliminates the possibility of null pointer exceptions, which can be a major source of errors in Dart code. Records are a new type that lets you aggregate multiple values of different types in a single function return. This makes it easier to work with structured data. Patterns are a new category of grammar that lets you match and destructure values. This makes it easier to work with complex data structures. Abstract data types are a new way to define data structures that cannot be created or modified directly. This makes it easier to create robust and reusable code. Class modifiers are a new set of keywords that let you control how a class or mixin can be used. This makes it easier to create flexible and extensible code.

These new features make Dart 3 a more reliable and productive language. If you are a Dart developer, I encourage you to learn more about these new features and how they can help you write better code.

Etornam Sunu Bright

June 12, 2023
Tweet

More Decks by Etornam Sunu Bright

Other Decks in Programming

Transcript

  1. Flutter & Dart Dart 3 Language Features: A New Era

    of Reliability and Productivity
  2. Dart 3 is the latest version of the Dart programming

    language. It introduces a number of new features that make it more reliable and productive. • Sound null safety • Records • Patterns • Sealed Classes • Class modifiers Features
  3. Sound null safety is a feature in Dart that prevents

    null pointer exceptions at runtime. It does this by making all variables non-nullable by default. This means that if you try to assign a null value to a variable, the compiler will throw an error. Sound null safety is a major improvement over the previous null safety model in Dart, which allowed variables to be nullable by default. What is sound null safety? Sound null safety
  4. Records are a new type in Dart that lets you

    aggregate multiple values of different types in a single function return. This makes it easier to work with structured data. Records are similar to classes in that they can contain fields, but they are different in several ways. Records are anonymous, meaning that they do not have a name. They are also immutable, meaning that their fields cannot be changed after they are created. Finally, records are structurally typed, meaning that their type is determined by the types of their fields. What are Records? Records
  5. final record = ('first', a: 2, b: true, 'last'); //Record

    type annotations are comma-delimited lists of //types enclosed in parentheses. // Returns multiple values in a record: (String, int) userInfo(Map<String, dynamic> json) { return (json['name'] as String, json['age'] as int); } final json = <String, dynamic>{ 'name': 'Dash', 'age': 10, 'color': 'blue', }; // Destructures using a record pattern: var (name, age) = userInfo(json); /* Equivalent to: var info = userInfo(json); var name = info.$1; var age = info.$2; */
  6. Patterns are a syntactic category in the Dart language, like

    statements and expressions. A pattern represents the shape of a set of values that it may match against actual values. They let you match and destructure values. This makes it easier to work with complex data structures. What are Patterns? Patterns
  7. ///Many patterns make use of subpatterns, sometimes called ///outer and

    inner patterns const a = '1'; const b = '2'; switch (obj) { // List pattern [a, b] matches obj first if obj is a list with two fields, // then if its fields match the constant subpatterns 'a' and 'b'. case [a, b]: print('$a, $b'); } ///Destructuring var numList = [1, 2, 3]; // List pattern [a, b, c] destructures the three elements from numList... var [a, b, c] = numList; // ...and assigns them to new variables. print(a + b + c);
  8. /// Variable declaration // Declares new variables a, b, and

    c. final (a, [b, c]) = ('str', [1, 2]); ///Why use patterns? //Without patterns, validation is verbose: var json = { 'user': ['Lily', 13] }; if (json is Map<String, Object?> && json.length == 1 && json.containsKey('user')) { var user = json['user']; if (user is List<Object> && user.length == 2 && user[0] is String && user[1] is int) { var name = user[0] as String; var age = user[1] as int; print('User $name is $age years old.'); } } //Validating incoming JSON var json = { 'user': ['Lily', 13] }; var {'user': [name, age]} = json;
  9. Only the base modifier can appear before a mixin declaration.

    The modifiers do not apply to other declarations like enum, typedef, or extension • abstract • base • final • interface • sealed • mixin Features
  10. /// ====>>>>>>> abstract classes ///To define a class that doesn’t

    require a full, concrete implementation of its ///entire interface, use the abstract modifier. ///Abstract classes cannot be constructed from any library, whether its own or ///an outside library. Abstract classes often have abstract methods. // Library a.dart abstract class Vehicle { void moveForward(int meters); } // Library b.dart import 'a.dart'; // Error: Cannot be constructed Vehicle myVehicle = Vehicle(); // Can be extended class Car extends Vehicle { double distance = 0.0; @override void moveForward(int meters) { // ... } }
  11. ///=======>>>>>>>>> base ///To enforce inheritance of a class or mixin’s

    implementation, ///use the base modifier. A base class disallows implementation ///outside of its own library. // Library a.dart base class Vehicle { void moveForward(int meters) { // ... } } // Library b.dart import 'a.dart'; // Can be constructed Vehicle myVehicle = Vehicle(); // Can be extended base class Car extends Vehicle { int passengers = 4; // ... } // ERROR: Cannot be implemented base class MockVehicle implements Vehicle { @override void moveForward() { // ... } }
  12. ///=======>>>>>>>> interface ///To define an interface, use the interface modifier.

    ///Libraries outside of the interface’s own defining library can ///implement the interface, but not extend it. // Library a.dart interface class Vehicle { void moveForward(int meters) { // ... } } // Library b.dart import 'a.dart'; // Can be constructed Vehicle myVehicle = Vehicle(); // ERROR: Cannot be inherited class Car extends Vehicle { int passengers = 4; // ... } // Can be implemented class MockVehicle implements Vehicle { @override void moveForward(int meters) { // ... } }
  13. ///===========>>>>>>sealed ///To create a known, enumerable set of subtypes, use

    the sealed modifier. /// This allows you to create a switch over those subtypes that is statically ///ensured to be exhaustive. sealed class Vehicle {} class Car extends Vehicle {} class Truck implements Vehicle {} class Bicycle extends Vehicle {} // ERROR: Cannot be instantiated Vehicle myVehicle = Vehicle(); // Subclasses can be instantiated Vehicle myCar = Car(); String getVehicleSound(Vehicle vehicle) { // ERROR: The switch is missing the Bicycle subtype or a default case. return switch (vehicle) { Car() => 'vroom', Truck() => 'VROOOOMM', }; }
  14. ///=======>>>>> final ///This prevents subtyping from a class outside of

    the current library. ///Disallowing both inheritance and implementation prevents subtyping entirely // Library a.dart final class Vehicle { void moveForward(int meters) { // ... } } // Library b.dart import 'a.dart'; // Can be constructed Vehicle myVehicle = Vehicle(); // ERROR: Cannot be inherited class Car extends Vehicle { int passengers = 4; // ... } class MockVehicle implements Vehicle { // ERROR: Cannot be implemented @override void moveForward(int meters) { // ... } }
  15. ///===========> mixins ///Mixins are a way of defining code that

    can be reused in multiple ///class hierarchies. They are intended to provide member implementations en masse. mixin Musical { bool canPlayPiano = false; bool canCompose = false; bool canConduct = false; void entertainMe() { if (canPlayPiano) { print('Playing piano'); } else if (canConduct) { print('Waving hands'); } else { print('Humming to self'); } } } To use a mixin, use the with keyword followed by one or more mixin names. class Musician extends Performer with Musical { // ··· entertainMe(); }
  16. You can combine some modifiers for layered restrictions. A class

    declaration can be, in order: 1. (Optional) abstract, describing whether the class can contain abstract members and prevents instantiation. 2. (Optional) One of base, interface, final or sealed, describing restrictions on other libraries subtyping the class. 3. (Optional) mixin, describing whether the declaration can be mixed in. 4. The class keyword itself. You can’t combine some modifiers because they are contradictory, redundant, or otherwise mutually exclusive: • abstract with sealed. A sealed class is always implicitly abstract. • interface, final or sealed with mixin. These access modifiers prevent mixing in. Combining modifiers Class modifiers
  17. • Inline classes • Primary constructors • Meta programming •

    Compilation to WebAssembly - Wasm • Native interop - java/kotlin/Objective C & Swift Coming soon
  18. “To build the most productive programming language for building fast

    apps on any platform” Dart long-term vision