Generics in dart

Generics in dart

ยท

3 min read

In Dart, generics are a way to create reusable classes, functions, and other types that work with multiple types of data. They allow you to write code that is flexible and can work with different types of data without having to create separate implementations for each type.

You can use generics by specifying a type parameter with angle brackets <> when defining a class, function, or other types. The type parameter acts as a placeholder for the actual type that will be used when the class or function is instantiated or invoked.

Here is an example of a generic class in Dart (simple way):

class MyList<T> {
    List<T> _list = [];
    void add(T item) {
        _list.add(item);
    }
    T get(int index) {
        return _list[index];
    }
}

In this example, the class MyList takes a type parameter T, which can be any type of data. The class has an internal list _list of type T, and two methods add and get that can add and get elements of the list respectively.

You can then use the class with different types like this:

final myList = MyList<int>();
myList.add(1);
myList.add(2);
print(myList.get(1));  // 2

final myStringList = MyList<String>();
myStringList.add("Hello");
myStringList.add("World");
print(myStringList.get(0));  // "Hello"

Here is another example of a generic class in Dart:

class TreeNode<T> {
  T value;
  TreeNode<T>? left;
  TreeNode<T>? right;
  TreeNode({required this.value});
}

The class TreeNode is defined with a generic type T, which is used to specify the type of the value stored in the node. The type T can be any valid Dart type, such as int, String, or a custom class.

You can use the generic class like this:

final root = TreeNode<int>(value: 1);
  root.left = TreeNode<int>(value: 2);
  root.right = TreeNode<int>(value: 3);
  root.left!.left = TreeNode<int>(value: 4);
  root.left!.right = TreeNode(value: 5);

Here is an example of a generic function in Dart:

T getMiddle<T>(List<T> list) {
  return list[list.length ~/ 2];
}

The function getMiddle is defined with a generic type T, which is used to specify the type of elements in the input list. Type T can be any valid Dart type.

You can use this function like this:

final middleInt = getMiddle([1, 2, 3, 4, 5]);
final middleString = getMiddle(['apple', 'banana', 'cherry']);

You can also use the generic types in interfaces, for example:

abstract class Cache<K, V> {
  V getByKey(K key);
  void setByKey(K key, V value);
}

In this example, the Cache interface defines two methods that use two generic types, K and V, to specify the types of the key and value stored in the cache. Classes that implement this interface can use any valid Dart types for K and V.

Conclusion

In conclusion, generics are a powerful feature in Dart that allows you to write code that is flexible and can work with multiple types of data. By using generics, you can create reusable classes, functions, and other types that can work with any type of data, without having to create separate implementations for each type. This makes your code more reusable, easier to maintain, and less prone to errors.

In addition to increasing code reusability, generics also make your code more readable and self-documenting. They make it clear to other developers what types of data a class, function, or other type is expected to work with, making it easier for others to understand and use your code.

Overall, generics are a valuable tool that every Dart developer should be familiar with. They allow you to write code that is more flexible, maintainable, and less prone to errors. So, next time you're writing a class or function in Dart, consider using generics to make your code more reusable and easier to maintain ๐Ÿ˜Š.

ย