---
title: "Dart Language Essentials"
description: "Mixins and the on keyword, and how iterables differ from lists."
tags: [flutter, dart, language]
---

## Mixins

A mixin is a block of behaviour you can attach to classes that otherwise have nothing in common, without putting them in the same inheritance chain.

### What a mixin is

In Dart, a **mixin** is a way to reuse code in multiple class hierarchies. It allows you to "mix in" methods and properties from one class to another without establishing an inheritance relationship.

### Why mixins exist

#### Dart has single inheritance

The primary reason for using mixins is that Dart, like many object-oriented languages, only supports **single inheritance**. This means a class can only directly extend one parent class:

```dart
class A {}
class B {}
class C extends A {} // Valid
class D extends A, B {} // Invalid - can't extend multiple classes
```

Mixins solve this limitation by providing a mechanism to reuse code across different class hierarchies without multiple inheritance.

#### Composition over inheritance

Mixins promote **composition over inheritance**, which is generally considered a better design practice. Instead of creating deep inheritance hierarchies, mixins allow you to compose functionality.

### Why not just use a class

#### A class would need multiple inheritance

If we used only classes without mixins, we would need multiple inheritance to achieve the same functionality, which Dart doesn't support:

```dart
// Without mixins, we'd want this (but it's not allowed):
class MyWidget extends StatelessWidget, AnimationSupport, LoggingSupport {}
```

#### Implementing an interface is not code reuse

While Dart allows implementing multiple interfaces, interfaces only define what methods a class should have, not how they are implemented:

```dart
class A {
  void methodA() { print("Method A"); }
}

class B implements A {
  @override
  void methodA() {
    // We have to reimplement the method
    print("Method A");
  }
}
```

With mixins, the implementation is reused:

```dart
mixin A {
  void methodA() { print("Method A"); }
}

class B with A {
  // Gets methodA implementation from mixin A
}
```

Flutter uses mixins extensively. For example, to add animation capabilities to a widget:

```dart
class MyAnimatedWidget extends StatefulWidget {
  @override
  _MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}

// Here we use SingleTickerProviderStateMixin to add animation capabilities
class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
  }

  // Rest of the implementation
}
```

This is much cleaner than trying to inherit all these capabilities or reimplement them.

With a mixin, `FileManager` is still free to extend something else:

```dart
mixin Logger {
  void log(String message) {
    print('Log: $message');
  }
}

class FileManager with Logger {
  void saveFile() {
    log('File saved successfully.');
  }
}

void main() {
  FileManager fm = FileManager();
  fm.saveFile();  // Output: Log: File saved successfully.
}
```

With a base class it works, but the one inheritance slot is now spent:

```dart
class Logger {
  void log(String message) {
    print('Log: $message');
  }
}

class FileManager extends Logger {
  void saveFile() {
    log('File saved successfully.');
  }
}

void main() {
  FileManager fm = FileManager();
  fm.saveFile();  // Works, but FileManager can't extend any other class
}
```

A mixin also has no constructor, so it adds nothing to object creation and cannot force constructor
arguments onto the classes that use it.

### How mixins differ from classes

1. **Declaration**: Mixins are declared using the `mixin` keyword instead of `class`
2. **Instantiation**: Mixins cannot be instantiated on their own (`new MyMixin()` is invalid)
3. **Usage**: Mixins are applied using the `with` keyword rather than `extends`
4. **Constraints**: Mixins can be restricted to work only with specific class types using the `on` keyword

```dart
mixin LoggerMixin {
  void log(String message) {
    print('LOG: $message');
  }
}

mixin ValidatorMixin {
  bool isValidEmail(String email) {
    return email.contains('@');
  }
}

class UserController with LoggerMixin, ValidatorMixin {
  void createUser(String email) {
    if (isValidEmail(email)) {
      // Create user
      log('User created with email: $email');
    } else {
      log('Invalid email: $email');
    }
  }
}
```

In this example, `UserController` benefits from both mixins without having to inherit from either, allowing for flexible code reuse across different parts of your application.

### Restricting a mixin with `on`

The `on` keyword restricts a mixin so it can only be applied to a specific class or its subclasses.

```dart
class Animal {
  void eat() {
    print("Eating");
  }
}

mixin Swimmer on Animal {
  void swim() {
    print("Swimming");
  }
}

class Fish extends Animal with Swimmer {
  // Valid
}
```

`Swimmer` can only be mixed into `Animal` or a subclass of `Animal`. This fails to compile because `Car` does not extend `Animal`:

```dart
class Car with Swimmer {
  // Compile-time error
}
```

#### Why use `on`

Use it when the mixin depends on methods or properties of a particular base class.

```dart
mixin Logger on Animal {
  void logEating() {
    eat(); // Safe because Logger requires Animal
  }
}
```

Without `on Animal`, Dart cannot guarantee that `eat()` exists on the class using the mixin.

In short: `on` restricts a mixin to specific classes or their subclasses. Use it when the mixin depends on functionality provided by the target class.

## Iterables vs lists

Both represent a sequence of elements. The difference is when those elements exist.

### The difference

#### Iterable

An `Iterable` is an abstract class in Dart that represents a collection of elements that can be accessed sequentially. Key characteristics include:

* It's a **base interface** that defines a way to access a sequence of elements
* You can't instantiate an `Iterable` directly (abstract class)
* It provides methods like `map()`, `where()`, `reduce()`, and `forEach()`
* It's **lazy**: operations on iterables don't execute until you actually iterate through the elements
* Elements are computed on-demand when accessed
* It doesn't necessarily store all elements in memory at once

```dart
// Example of working with an Iterable
Iterable<int> generateNumbers() sync* {
  for (int i = 0; i < 10; i++) {
    yield i;  // Elements are generated one at a time
  }
}

void main() {
  final numbers = generateNumbers();
  final evenNumbers = numbers.where((num) => num % 2 == 0);
  // No computation has happened yet until we iterate

  for (var num in evenNumbers) {
    print(num);  // Computation happens here, on-demand
  }
}
```

#### List

A `List` is a concrete implementation of `Iterable` with the following characteristics:

* It's an **ordered** collection that stores elements in a specific sequence
* Elements can be accessed by index using `[]` operator
* It has a fixed length or can be dynamic (growable)
* All elements are stored in memory at once
* Provides additional methods like `add()`, `removeAt()`, `insert()`
* You can directly instantiate a `List`

```dart
void main() {
  // Creating a List
  List<int> numbers = [1, 2, 3, 4, 5];

  // Accessing by index
  print(numbers[2]);  // 3

  // Adding elements
  numbers.add(6);

  // Methods that modify the list
  numbers.remove(3);
  numbers.insert(0, 0);
}
```

### Side by side

1. **Instantiation**: You can directly create a `List` but not an `Iterable` (abstract)
2. **Memory Usage**: `List` stores all elements in memory while `Iterable` can generate elements on-demand
3. **Operations**: `List` has methods to modify the collection (add, remove), while `Iterable` primarily provides methods for traversal and transformation
4. **Random Access**: `List` supports accessing elements by index, while `Iterable` only supports sequential access
5. **Evaluation**: `List` operations are evaluated immediately, while `Iterable` operations are lazy (evaluated when needed)

### When to use which

1. **Performance Optimization**: Using `Iterable` for large datasets or streams of data can improve app performance
2. **Memory Management**: Working with large collections efficiently
3. **Reactive Programming**: Working with streams and asynchronous data flows
4. **Functional Programming**: Using higher-order functions like `map`, `where`, and `reduce`

For example, when displaying a large list of transactions in a finance app, you might use `Iterable` operations to filter and transform the data before converting to a `List` for display.
