Exploring Dart 3.0’s New Class Modifiers with Real-World Examples
Published: 2023-07-19 11:00:00

---
title: Exploring Dart 3.0’s New Class Modifiers with Real-World Examples
published: true
description: In this article, we will delve into these modifiers using real-world object examples, showcasing their practical applications and benefits.
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zchbkoo2fo0vb7amk9g.jpeg
published_at: 2023-07-19 21:00 +1000
canonical_url: https://dom.jocubeit.com/exploring-dart-30s-new-class-modifiers-with-real-world-examples
---
Dart 3.0 introduces a set of powerful [class modifiers](https://dart.dev/language/class-modifiers) that provide developers with more control over inheritance, implementation, and type hierarchy. These modifiers, namely `base`, `interface`, `final`, and `sealed`, complement the existing modifiers `abstract` and `mixin` to offer distinct guarantees and restrictions when applied to classes or mixins.

In this article, we will delve into these modifiers using real-world object examples, showcasing their practical applications and benefits.

## The base Modifier

The `base` modifier ensures the enforcement of inheritance and implementation within a `class` or `mixin`'s own library. It offers several guarantees such as:

- The base class constructor is invoked whenever an instance of a subtype is created.
- All private members implemented in the base class are inherited by subtypes.
- The addition of newly implemented members in the base class does not break existing subtypes unless a subtype already declares a member with the same name and incompatible signature.

To illustrate this, let’s consider the example of a Vehicle class defined in the library `base_vehicle.dart`. The `base` modifier is applied to ensure that the Vehicle class is extended within its own library, disallowing implementation outside of it.

```dart
// Library base_vehicle.dart
base class Vehicle {
  void moveForward(int meters) {
    // ...
  }
}

// Library test.dart
import 'base_vehicle.dart';

// Example usage
Vehicle myVehicle = Vehicle(); // Can be constructed

base class Car extends Vehicle {
  int passengers = 4;
  // ...
}

// ERROR: Cannot be implemented
base class Truck implements Vehicle {
  @override
  void moveForward() {
    // ...
  }
}
```

## The interface Modifier

With the `interface` modifier, developers can define interfaces in Dart. These interfaces can be implemented by libraries outside their defining library but cannot be extended. The key guarantees provided by the `interface` modifier are:

- Instance methods within the interface always invoke known implementations from the same library.
- Other libraries cannot override methods in a way that could cause unexpected behaviour within the interface class.

Let’s consider an example where a Vehicle `interface` is defined in `vehicle_interface.dart` and implemented in another library, `test.dart`.

```dart
// Library vehicle_interface.dart
interface class Vehicle {
  void moveForward(int meters) {
    // ...
  }
}

// Library test.dart
import 'vehicle_interface.dart';

// Example usage
Vehicle myVehicle = Vehicle(); // Can be constructed

// ERROR: Cannot be inherited
class Car extends Vehicle {
  int passengers = 4;
  // ...
}

// Can be implemented
class Truck implements Vehicle {
  @override
  void moveForward(int meters) {
    // ...
  }
}
```

## The final Modifier

The `final` modifier closes the type hierarchy, preventing subtyping from external classes. It disallows both inheritance and implementation, ensuring that the API remains stable and instance methods are not overwritten by third-party subclasses. However, `final` classes can still be extended or implemented within the same library. It is worth noting that the `final` modifier encompasses the effects of the `base` modifier, requiring any subclasses to be marked as `base`, `final`, or `sealed`.

Consider the following example where a `final` Vehicle class is defined in `final_vehicle.dart`, and its usage is demonstrated in `test.dart`:

```dart
// Library final_vehicle.dart
final class Vehicle {
  void moveForward(int meters) {
    // ...
  }
}

// Library test.dart
import 'final_vehicle.dart';

// Example usage
Vehicle myVehicle = Vehicle(); // Can be constructed

// ERROR: Cannot be inherited
class Car extends Vehicle {
  int passengers = 4;
  // ...
}

class Truck implements Vehicle {
  // ERROR: Cannot be implemented
  @override
  void moveForward(int meters) {
    // ...
  }
}
```

## The sealed Modifier

The `sealed` modifier allows developers to create a known and enumerable set of subtypes, ensuring exhaustive handling through switch statements. Sealed classes cannot be extended or implemented outside their defining library but can have factory constructors and define constructors for their subclasses. Subclasses of sealed classes, however, are not implicitly abstract.

Let’s explore a practical example of a `sealed` Vehicle class with several subclasses:

```dart
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',
  };
}
```

## What have we learned?

Dart 3.0’s new class modifiers, including `base`, `interface`, `final`, and `sealed`, will empower developers to design more robust and maintainable code. By using real-world examples, we have demonstrated how these modifiers offer practical solutions for enforcing inheritance, implementing interfaces, closing the type hierarchy, and ensuring exhaustive handling of subtypes. Incorporating these modifiers into your Dart projects will enhance code clarity, prevent unexpected behaviours, and contribute to overall code quality and reliability.

**Other information**

This post originally appears on my personal web site at https://dom.jocubeit.com/exploring-dart-30s-new-class-modifiers-with-real-world-examples

I used another free credit at STOCKIMG.AI to generate a horizontal poster using disco diffusion for the article poster image. This time I used the image from my second post as the primer, with some words about class modifiers, inheritance, type hierarchy and interfaces. The image above is the generated result. Again, I was expecting something similar to the second image and the result didn’t disappoint. With all three articles being in the same vein, I decided to use it.