Extension Methods

Learn to extend a core-class or a third-party's functionalities using Extension Methods.

Introduction

Dart Extensions were first introduced in Dart 2.6 as a preview but they have been officially released in Dart 2.7. The extensions feature helps to add functionality to existing libraries.

Sometimes you may want to add utility method(s) in a third-party library or in a core class like String for your convenience. However, it is not always possible to add your methods in those classes.

One possible solution is to write utility and/or wrapper classes with static methods and members. But the downside to this approach is that these extra classes can bloat your codebase and increase the number of objects.

In such scenarios, the extensions feature is useful. It may appear like wrapper classes, but they are different. In wrapper classes, the object is explicitly passed as an argument to the static methods; however, extensions implicitly extend the type.

Defining Extensions

In Dart, extensions are defined inside one code block. The code block begins with extension followed by an optional name for the extension, the on keyword, and the data type.

Let’s add custom functionality to the List data type. We can utilize the generic type T to support different varieties of data types.

Do not worry if you are unfamiliar with generics. We will discuss generics in detail later on in the course.

There are two options for writing the extension code block.

//Option #1
extension<T> on List<T> {}

//Option #2
extension<T> MyList on List<T> {}

Option #1 is the logical avenue when extensions are defined in the same file as they are intended to be used. The same extension can be defined in another way. See Option #2.

In Option #2, the extension is named MyList. It is optional to name the extension. Option #2 is a better choice when extensions are written in a separate file or in the library. It is also a better choice when extensions and are being imported into another Dart file.

Types of Extension

Dart supports three types of extension implementations:

  • Extension Methods
  • Extension Operators
  • Extension Properties
extension<T> on List<T> {
  //extension methods

  //extension operators

  //extension properties
}

In this lesson, we will explore Extension Methods.

Extension Methods

In this section, we will add two extension methods for the List data type. With the given List of prices, we will apply it to both examples. In the first example, we will learn to write an extension method for List with the help of a very trivial example. In the second example, we’ll modify the list items with the help of the extension method.

Example #1

In this example, you will learn to 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.

//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());
}

Example #2

In this example, you will learn to use the extension method to modify the list items. Let’s assume you want a method provided by the List class to append a dollar sign ‘$’ for each price item listed. Since this functionality is specific to this example, adding it to the core List class may not make sense. Such are the scenarios where Dart’s extensions functionality shines. This particular method can be added to behave as if the core-class provided it.

The extension method priceLabels(String symbol) iterates over the price listing, and appends a symbol prefix for each price.

Now run the code snippet below to see the extension method priceLabels(...) in action.

extension<T> on List<T> {
//Extension Method: Adding $ prefix
List<String> priceLabels(String symbol) =>
this.map((item) => "$symbol${item}").toList();
}
//Let's use `priceLabels()`, and pass the '$' symbol
//that we wish to be prefixed with items of list `prices`.
void main() {
//List of prices
List prices = [1, 1.99, 4];
print("\nPrice listing with \$ prefix");
//The $ symbol is passed
print(prices.priceLabels("\$"));
}