Extension in Dart (Flutter)

In a recent release of Dart 2.6, the language introduced a new function, static extension or static extension methods, which allows you to add new methods to existing types. Why do we need extension? How to use them and what are they good for?







Introduction



To begin with, what is extension in general? Extension is syntactic sugar that extends an existing class in a place different from the class declaration module.



In programming, extension methods have been around for a long time, so they got to dart. Extension is actively used in languages โ€‹โ€‹such as C #, Java via Manifold, Swift, Kotlin and many others.



Problem



Let's say we have a catchError method, which is just awful and needs to be rewritten to a new cool function. Suppose that he uses a function of any type as an argument, instead of a strictly typed function or a function type check, and this happens because 8 months ago when developing this functionality, it was logical at that time.



The first thing that comes to mind is to rewrite this function, but here we are faced with the problem that it occurs too often in the project, and changing the function will lead to the inoperability of the entire project.



Well, if the first option is not for us. suitable, for logical reasons, then I can implement a new Future function that will meet all my requirements.



abstract class Future<T> { ... /// Catches any [error] of type [E]. Future<T> onError<E>(FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(...   -  ...); } ... }
      
      





and Iโ€™ll call her like this:



 Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...);
      
      





Unfortunately, I cannot add this function to the Future class. If I do this, I will also add it to the Future interface, and any other class that implements this interface will be incomplete and will no longer compile.



Well, another option is to implement a third-party function that will look like this:



 Future<T> onFutureError<T, E>(Future<T> source, FutureOr<T> handleError(E error, StackTrace stack)) => source.catchError(... - ...);
      
      





And her call would look like this:



 Future<String> someString = ...; onFutureError(someString, (FormatException e, s) => ...).then(...);
      
      





Great, everything works! But itโ€™s sad that it began to be terribly read. We use methods. which are implemented inside the class, so they are called -.doingSomething (); This code is understandable, I just read it from left to right and stand in my head a sequence of events. Using a helper function makes the code cumbersome and less readable.



Well then, I can implement a new class and let users wrap their old interface with improved functionality.



 class CustomFuture<T> { CustomFuture(Future<T> future) : _wrapper = future; Future<T> _wrapper; Future<T> onError<E>(FutureOr<T> handleError(E error, StackTrace stack)) => _wrapper.catchError(...-     ...); }
      
      





and the call will look like this:



 Future<String> someString = ...; CustomFuture(someString).onError((FormatException e, s) => ...).then(...);
      
      





Looks great!



Solving a problem with extension



As soon as we stop programming in pascal and return to 2019, the implementation of this functionality will be reduced to this size:



 extension CustomFuture <T> on Future<T> { Future<T> onError<E>( FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(...something clever...); }
      
      





and this is what the call will look like:



 Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...);
      
      





That's all! The solution to this problem took only 5 lines of code. You. You may wonder what kind of magic is and how it works.



In fact, it behaves just like the wrapper class, although in reality it is just an auxiliary static function. Extension allows you to let go of explicit wrapper writing.



This is not a wrapper



The extension design works in such a way that it looks like a declaration of an existing class, but acts as if it were a wrapper with a private _wrapper. But there is one advantage compared to the wrapper class, this is accessing the class itself directly, rather than accessing the _wrapper wrapper class.



This feature was not made for the sake of features, but as I said earlier, extensions are indeed a more convenient way to call static functions. This means that there is no wrapper object.



It's All Static



I said โ€œstatic extension methodsโ€ above, and I did it for a reason!



Dart is statically typed. The compiler knows the type of each expression at compile time, so if you write user.age (19) and age is an extension, then the compiler must figure out what type is wrapped in the given object in order to find the type of the whole call.



What problems can arise?



The simplest example of problems with extension is when you have more than one extension in its scope. Basically, the winner is the extension closest to the actual type of expression that you are calling the member, with some reservations.



The easiest way to solve the problem is to connect strictly the extension you need, or you can use the extension explicitly:



 ... List list = ...; MyList(list).printlist(); SomeList(list).printlist(); ... extension MyList on List { void printlist() { print(...- ...); } } extension SomeList on List { void printlist() { print(...-  ...); } }
      
      





Summary





If the output of the extension fails due to conflicting extensions, then you can do one of the following:



  1. Apply the extension explicitly.
  2. Import the conflicting extension with the prefix, because then it is not available for implicit calling.
  3. Do not import a conflicting extension at all.


That's all! You can use extension to its full potential.



And of course, useful links:



Website flutter

Dart website

Where can I read more about extension

Telegram channel where I talk about all the newest in the world of Flutter and not only



All Articles