Introducing Dart 2 language features: mixins, enums, and more
Tags: dart, flutter, google, mobile
Published: 2020-10-23 21:18:59

*Dart is an object-oriented, class-based language used with Flutter. Dart's recent update introduced new features like enums, mixins, extensions, and more. Today, we explore the most important Dart 2 updates with code examples.*

___

**Dart** is an object-oriented, class-based, simple, and clean language. Google’s popular mobile framework, Flutter, uses Dart to implement **high-quality native applications**. In 2018, Dart 2 was released with all sorts of new features that make it much safer, more expressive, and more usable.

This update modified the basics of the Dart language, libraries, build system, and web development tools. 

Flutter and Dart are a powerful combination, so it’s important to understand all that Dart 2 can do and get the full potential of the language. Today, we’ll introduce you to the **most important new language features** of Dart 2 to take your web applications to the next level.

> *To be most successful with this article, a basic knowledge of Flutter and Dart is recommended. Check out our article [Flutter Tutorial: the beginner's guide to cross-platform apps](https://www.educative.io/blog/flutter-tutorial) before continuing here.*

**Today, we will go over:**
* [Dart 2 Extensions](#extensions) 
* [Dart 2 Enums](#enums)
* [Dart 2 Mixins](#mixins)
* [Dart 2 Generics](#generics)
* [Asynchrony in Dart](#async) 
* [What to learn next](#next)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3fdvtg0uwru2d4wml2kx.png)

<br>

<a name="extensions"></a>

## Dart Extensions 
Dart extensions were officially released with Dart 2.7. The extensions feature **adds functionality** to **existing Dart libraries**. The extensions feature is useful when you want to add utility method(s) in a third-party library or a core class.

With the first version of Dart, it was not always practical to add methods in those classes. Extensions help by **implicitly extending the type** as opposed to the old style where the object was explicitly passed as an argument to static methods.

Extensions are defined inside one block of code that begins with `extension` and contains a name for the extension, the `on` keyword, and the data type. Dart supports **three types of extensions** that we will go over in more detail below:

```dart
extension<T> on List<T> {
  //extension methods
  //extension operators
  //extension properties
}
```

<br>

### Extension methods
Extension methods allow you to add new members to existing types. You might already be using extension methods. For example, when using code completion in an IDE, it will suggest an extension method. Extension methods are located in libraries. 

> You use them by importing the right library and using them like an ordinary method.


Let’s see an example to understand extension methods. Below, we will write an extension method for the `List` data type. The extension method `priceList()` returns the price listing in the same condition. This method demonstrates how extensions implicitly extend the type using `this`.

```dart
//Local extension method
extension<T> on List<T> {
  //Extension Method demonstration
  List<T> priceList() => this.map((item) => item).toList();

}

void main() {
  //List of prices
  List prices = [1, 1.99, 4];

  print("Price listing:");

  //priceList() is being called on `prices` list 
  //and returns the list of prices
  print(prices.priceList());
}
```

> Output is "Price listing: [1, 1.99, 4]"

<br>

### Extension operators
Dart provides support for operators as well. Below, we will define an operator extension for the `^` operator. We assume this operator increases the price by the `n` times, where `n` is the passed argument.

The `operator` keyword declares an extension operator. It is followed by the operator sign. In the following example, the `this` list is iterated over to multiply each item by `n`, and then the updated list is returned.

```dart
extension<T> on List<T> {
  //Extension Operator: Hike up the price by n
  List<num> operator ^(int n) =>
    this.map((item) => num.parse("${item}") * n).toList(); 
}
```

The operator `^` is applied to the `prices` list. The operator `^` multiplies each item in `prices` by 3 and returns. The updated list is then printed using the `print()` method.

```dart
void main() {
  //List of prices
  List prices = [1, 1.99, 4];
 
  print("\nPrice listing after hiking up prices 3x of the original value");
 
  //argument is passed after the operator sign
  print(prices ^ 3);
}
```

This gives us the output below:

```dart
Price listing after hiking up prices 3x of the original value
[3, 5.97, 12]
```


<br>

### Extension property 
Dart also provides support for Properties. In the extension below, we add a property that returns the total number of printed price labels needed for a price listing. Let’s assume we want to print 3 labels for each price amount in the list `[1, 1.99, 4]`.

An extension property definition has three parts: the type of data to be returned by the property, the `get` keyword, and the name of the property. For example:

`<return_type> get <property_name> => //implementation`

The number of labels is of type `int`, and the property name is `labelCount`. We need 3 labels for each item, so we need three times the total size of the list. We can calculate the number of total labels as `length * 3`. The extension has implicit access to the `length` property.

```dart
extension<T> on List<T> {
  //Extension Property: 3 printed labels for each price.
  int get labelCount => length * 3;
}
```

The property `labelCount` is called on the price listing `prices`.

```dart
void main() {
  //List of prices
  List prices = [1, 1.99, 4];
 
  print("\nNumber of Printed Labels:");
  print(prices.labelCount);
}
```

This gives us the following output:

```dart
Number of Printed Labels:
9
```

___

<a name="enums"></a>

## Dart Enums
Enumerated Types (a.k.a. Enums) were added with the release of Dart 1.8. Enums act like a class that represent a fixed number of constant values. For example, you could have an app that fetches data from a remote server. The app shows one of the following statuses:
* **done:** The app received the response successfully.
* **waiting:** The app is waiting for the response.
* **error:** The app received an error from the server.

The above responses can be declared using the `enum` keyword:

```dart
enum Status {
  done,
  waiting,
  error, //This comma is optional
}
```

Let’s understand this better with an example and pretend we have a weather application. We need to represent states of the weather: sunny, cloudy, and rainy.

We could represent these states with a `const` keyword.

```dart
const SUNNY = 'Sunny';
const CLOUDY = 'Cloudy';
const RAINY = 'Rainy';
```
 
Or, we could use enumerated types with the `enum` keyword.
```
enum Weather {
  sunny,
  cloudy,
  rainy,
}
```

<br>

### Switch block with Enums
We can use the `switch` block for enums, and it requires case-blocks for all members of our `enum` class and a `default` block if a case-block implementation is missing, otherwise, you get a compilation error. Take a look at the example below.

> **Note:** `switch` block implementations can be done for constants and enums. However, enums are preferred when you do not want to lose an opportunity to handle a particular case.

```dart
//Using Enums to display weather information
enum Weather {
  sunny,
  cloudy,
  rainy,
}
void main() {
  var weather = Weather.sunny;

  //Following code will complain about if all members are not present
  //Use default-block when all case-blocks are not available
  switch (weather) {
    case Weather.sunny:
      print("Sunny weather today!");
      break;
    case Weather.cloudy:
      print("Cloudy today!");
      break;
    case Weather.rainy:
      print("Rainy and gloomy weather.");
      break;

    default:
      print("Current weather:${weather}");
  }
}
```

___

> ## Keep the learning going.
> 
> Learn how to **develop web applications using Dart** without scrubbing through videos or documentation. Educative's text-based courses are easy to skim and feature live coding environments, making learning quick and efficient. By the end of this course, you’ll be able to use this language in your own Flutter projects.
> 
> <b>[Developing Web Applications with Dart](https://www.educative.io/courses/developing-web-applications-with-dart)</b>
</div>
___

<a name="mixins"></a>

## Dart Mixins

Mixins allow our Dart code to be **reusable across separate classes**. It is far more efficient to reuse code from classes that share common behaviors. A mixin class contains methods used by other classes, but it is not their parent. Therefore, we can use the code from a class without inheriting from it, unlike interfaces and abstract classes.

Mixins are declared using the `mixin` keyword:

```dart
mixin SharedBehavior {
 }
```
The **syntax of mixins** is simple. Below, `B` is the parent class to `A`.` C` is the mixin with methods that `B` can implement.

```
class A extends B with C {
    //Implement methods from B & C

}
```

<br>

### Mixins example

Let’s understand this better with an example. Say we have different people with different occupations: artist, engineer, doctor, and athlete. We can assume that the four types of people share a combination of common behaviors (like sketching, reading, exercise, boxing, etc.) in addition to inheriting the class `Person`. 

> In other words, each type of person is extending the `Person` class and one or more shared behaviors.

Overlapping common behaviors like these can be extracted into mixins. We will create mixins for these behaviors. For example, the `Sketching` mixin defines the common `sketch()` method. This method takes a `message` parameter.

```
mixin Sketching {
  sketch(String message) {
    print(message);
  }
}
```

Let's see our example in code. Below, in the `main()` method, each class’ object is created and method(s) are called for their shared behavior which is implemented using Mixins.

```dart
//Person class
abstract class Person {
  int age;
  int name;

  eat() {}
  sleep() {}
}

//Artist class
class Artist extends Person with Sketching {
  sketchLandscape() {
    sketch("Making landscapes sketches");
  }
}

//Engineer class
class Engineer extends Person with Sketching, Reading {
  sketchBuildings() {
    sketch("Sketching engineering drawings");
  }

  readResearchPaper() {
    String topic = "Building Construction";
    dailyReading(topic);
  }
}

//Doctor class
class Doctor extends Person with Reading, Exercise {
  readReports() {
    String topic = "flu";
    dailyReading(topic);
  }

  workout() {
    running(1);
    weightTraining(10);
  }
}

//Athlete class
class Athlete extends Person with Exercise {
  generalRoutine() {
    running(2);
    weightTraining(20);
  }
}

//Boxer class
class Boxer extends Athlete with Boxing {
  punchPractice() {
    punch(100);
  }

  routineExercise() {
    running(4);
    weightTraining(40);
  }
}

//Mixins

//Sketching mixin
mixin Sketching {
  sketch(String message) {
    print(message);
  }
}

//Reading mixin
mixin Reading {
  dailyReading(String topic) {
    print("Daily reading on ${topic}");
  }
}

//Exercise mixin
mixin Exercise {
  running(int mile) {
    print("Daily run of ${mile} mile(s)");
  }

  weightTraining(int weights) {
    print("Lifting ${weights} lbs");
  }
}

//Boxing
mixin Boxing on Athlete {
  punch(int n) {
    print("Boxer practicing ${n} punches");
  }
}

void main() {
  print("Artist");
  Artist artist = Artist();
  artist.sketchLandscape();

  print("\nEngineer");
  Engineer engineer = Engineer();
  engineer.sketchBuildings();
  engineer.readResearchPaper();

  print("\nDoctor");
  Doctor doctor = Doctor();
  doctor.readReports();
  doctor.workout();

  print("\nBoxer");
  Boxer boxer = Boxer();
  boxer.punchPractice();
  boxer.routineExercise();
}
```

___

<br>

<a name="generics"></a>

## Dart Generics
Generics are used to apply **stronger type checks at compile time**. They also enforce type-safety. Generics help write reusable classes and methods/functions for different data types. Generics in Dart are similar to Java generics or C++ templates.

> **Definition:** Type Safety is a programming concept that allows a memory block to contain only one type of data.

Dart’s collection can hold different data types in one collection, but this can lead to crashing the program if a particular data type is not handled appropriately.  Generics can solve this problem by **enforcing one data type to the collection**. 

Let’s learn how to declare type-safe collections. To ensure type safety, the angular brackets `<>` with data type enclosed, declare the collection of the given data type. 

```dart
CollectionType <dataType> identifier = CollectionType <dataType>();
```

Generics are *parameterized*, so they use type variable notations to restrict the type of data. We commonly represent these type variables with single letter names, such as:
* **E:** represents the element type in a collection, i.e. `List`
* **R:** represents the return type of a function or method
* **K:** represents the key type in associative collections, i.e. `Map`
* **V:** represents the value type in associative collections, i.e. `Map`

> **Note:** We can also represent generics with descriptive names like `Product` or `Inventory` 
Take a look at an example of the single-letter name generics implementation. 

```dart
import 'dart:collection';

//Demonstrating use of single letter for generics

//A class for grocery product
class Product {
  final int id;
  final double price;
  final String title;
  Product(this.id, this.price, this.title);

  @override
  String toString() {
    return "Price of ${this.title} is \$${this.price}";
  }
}

//A class for product's inventory
class Inventory {
  final int amount;

  Inventory(this.amount);

  @override
  String toString() {
    return "Inventory amount: $amount";
  }
}

//Custom type variables- Single letter
class Store<P, I> {
  final HashMap<P, I> catalog = HashMap<P, I>();

  List<P> get products => catalog.keys.toList();

  void updateInventory(P product, I inventory) {
    catalog[product] = inventory;
  }

  void printProducts() {
    catalog.keys.forEach(
      (product) => print("Product: $product, " + catalog[product].toString()),
    );
  }
}

//Demonstrating single letter
void main() {
  Product milk = Product(1, 5.99, "Milk");
  Product bread = Product(2, 4.50, "Bread");

  //Using single letter names for Generics
  Store<Product, Inventory> store1 = Store<Product, Inventory>();
  store1.updateInventory(milk, Inventory(20));
  store1.updateInventory(bread, Inventory(15));
  store1.printProducts();
}
```

> Output:
> Product: Price of Bread is $4.5, Inventory amount: 15
> Product: Price of Milk is $5.99, Inventory amount: 20

___

<bR>

<a name="async"></a>

## Asynchrony in Dart
Asynchronicity allows multiple things to happen at the same time. In Dart, asynchronous operations can perform time-consuming operations and allow for their processing to finish at a later time.

Dart provides two ways to handle events/requests asynchronously. Dart’s `dart:async` library provides support for asynchronous programming with `Future` and `Stream` classes. 
* **Future objects:** represent the results of asynchronous operations. This is like a promise for a result to arrive in the future.
* **Stream objects:** provides a sequence of events that are either a value or an error.

<br>

### `Future` objects

Let’s explore future objects. Asynchronous operations results are returned as `Future` objects. The future object is represented as `Future<T>`, where `T` is the type of results returned. When we need the result of a completed Future, we can use either:
* `await` and `async`
* The `Future` API

We use the `await` and `async` keywords together. The function that is expected to perform the expensive work will be marked with the keyword `async`. The expensive call is prefixed by the keyword `await` inside the function. 

The program will suspend when `await` is called, when a function returns, or when it reaches the end of the function. Let’s see an example of `async` and `await` below:

```
// Expensive function could be a function that takes
// long time to process data and return results.
// Assume this function takes long time to return in real-world
String getExpansiveData() {
  return "I'm expansive data";
}

// This is the asynchronous function that makes the expensive
// data call and prints the results.
Future<void> makeDataCall() async {
  var data = await getExpansiveData();
  print(data);
}
//----END----//

//Entry point function
void main() {
  makeDataCall();
}
```

> Output: I'm expansive data

Above, the `Future` keyword before the function `makeDataCall()` means that this function will be executed asynchronously. Therefore, it will be suspended when it encounters `await`.

The `makeDataCall()` returns a `Future` of type `void` since there is nothing returned by the function. It calls the `getExpansiveData()` method with the keyword `await`, which returns the string `I'm expansive data`. The method `makeDataCall()` prints the results with the function`print()`.

> The `Future` API can also be used to execute asynchronous operations. In the `Future` API, the `then()` method registers a callback, which fires upon the completion of `Future`. 
>
> There are two variants of the Future API.
> * `Future<String>`: Future returning `String` data type .
> * `Future<void>`: Future returning `void`.

<br>

<a name="next"></a>

## What to learn next 
Congrats! You should now have a good understanding of what Dart 2 brings to the table. With Dart in our Flutter projects, we can make high-quality native applications, and these new features take your Dart skills to the next level. 

But there is **still more to learn** about Dart 2 to truly use this language to its full potential. Your next learning steps are the following concepts:
* Callable Classes
* Generator Functions
* Dart Libraries 
* Generic Collections 
* API and Streams in Dart
* OS Variables/`Platform` Class
* Encryption in Dart (`encrypt` package) 

To get started with these intermediate Dart 2 concepts, check out Educative’s course **[Developing Web Applications with Dart](https://www.educative.io/courses/developing-web-applications-with-dart)**. You will dive deep into Dart 2 language features with hands-on code. Gain confidence using everything from extensions to callable classes and beyond. By the end, you’ll be able use this language in your own Flutter projects. You can even **earn a certificate** and add Dart  skills to your resume! 

*Happy learning!*

<br>

### Continue reading about mobile development and Flutter
* [Flutter Tutorial: the beginner's guide to cross-platform apps](https://www.educative.io/blog/flutter-tutorial)
* [Android Tutorial: How to Develop an Android App](https://www.educative.io/blog/how-to-develop-an-android-app)
* [Build modern, offline apps with Progressive Web Apps
](https://www.educative.io/blog/build-modern-apps-progressive-web-apps)