The potential of types and extensions in Dart

Sergio Fraile
Flutter Community
Published in
5 min readJan 31, 2020

Recently I watched with my team one of the videos from Kotlinconf and I found it pretty interesting. Ever since I wanted to write about those concepts for my new favorite platform: Flutter.

The talk, in particular, is The Power of Types by Danny Preussler, and if you are interested, you can watch it here: https://youtu.be/t3DBzaeid74

So, what was the talk about? Danny talks about the history of programming languages and how types were born and how we have been moving between weakly typed languages and strong typed languages through time.

Not getting into if I agree or not with everything mentioned in the talk, I do think there are some interesting takeaways:

  • We are pretty obsessed using primitives most of the times.
  • Types can make our code more expressible and readable.
  • We can improve the discoverability of errors during compilation time.

Also and before diving in into this topic, there are some interesting quotes that Danny was showing during his talk and I will be randomly throwing them into the post.

A type is a concise, formal description of the behavior of a program fragment.

Primitives obsession

I didn’t realize about this myself until watching the talk, but it is absolutely true; I use primitives for everything… 😱

Let’s imagine we have the class Person defined in Dart:

Stop for a second to read it. Is it a name really a String? Can a name be formed for something else than characters? What about age, is there a need to contemplate numbers higher than 150? Can we have a negative age?

Well-typed expressions do not go wrong.

Robert Miner

The code is not very expressive, right? Also when we create an instance of Person, the autocompletion tells us that we are waiting for a parameter of type String and a parameter of type int. What are those? What am I suppose to pass as a parameter to instantiate that class?

In here you may argue that we could have named parameters, and I agree, because we understand the concepts of name and age; but computer programming can sometimes be more obfuscated than that and not everybody is good at naming methods, functions and variables.

How could we do this code better? We could use typedef to create an alias of the type as such:

typedef Name = String;
typedef Age = int;

And then update our Person class as follows:

class Person {
final name: Name;
final age: Age;
...
}

Now, I’m aware this previous example was a little bit too easy, you may be asking yourself if we do really need this. Let me illustrate it with another example. Let’s supposed we want to load a resource. We would probably write something like this:

Resource loadResource(location: String) { }

But, what is a location? Does a String type really reflect what a location is? If we rewrite it with some typedefs, we get a much more descriptive API:

typedef LocalUri = String;
typedef URL = String;
typedef AssetName = String;
Resource loadResource(location: LocalUri) { }
Resource loadResource(location: URL) { }
Resource loadResource(named: AssetName) { }

Wouldn’t it be wonderful? Well, I have some bad news…

The current status of typedef

Although typedef currently exists in Dart, it doesn’t do exactly what we are looking for with our previous example.

So what does typedef do at the moment? It allow us to specify alias types to executable parts of the code, such as functions. This is still cool and useful though. Suppose you want to define a callback, we could do it the following way:

typedef ImageDecoderCallback = void Function(Image result);

This is actually an example taken from the Flutter documentation itself.

Don’t put in name what can be in type.

You may be a bit confused, why was I talking about something that Dart currently doesn’t support? Well, Dart is still a young language and therefore still growing and evolving. It seems I’m not the only one that wish to see this feature in Dart and so the (awesome) Dart team is currently working on it, you can check its status here 👇🏼

If you are wondering about it, Swift and Kotlin both are able to use typedef for mostly anything and they take a great advantage from that. If you believe there’s something missing in Dart that is important, I would really encourage you to open an issue on github or vote for an existing issue (this helps a lot the Dart team to prioritise).

We haven’t talk about extensions yet…

You are right, after all this the title of the post mentions extensions but we have only talked about type aliases so far, so… what’s going on?

Encoding the type [..] into the name [..] is brain damaged, the compiler knows the types.

Linus Torvalds

You have probably already heard about extensions in Dart (available from Dart 2.7). We are not going to cover what are the extensions in here, so if you are curious, check the official documentation here. However, we are going to see how we could get advantage of the extensions when combined with type aliases. At the moment is more a theoretical exercise (remember you can already do this in Swift and Kotlin).

The interesting part of having extensions working with types aliases is that we can apply this functions only to particular subtypes.

Given we need to create a City class as an example, let’s suppose we could have it this way:

typedef Name = String;
typedef Population = int;
typedef Celsius = int;
typedef Fahrenheit= int;
class City {
final name: Name;
final population: Population;
final temperature: Celsius;
...
}

We could have an extension to convert from Celsius to Fahrenheit:

extension on Celsius {
Fahrenheit toFahrenheit() {
return this * (9/5) + 32;
}
}

This way the toFahrenheit method would only exist for parameters of type Celsius. It seems a pretty good way to keep our APIs clean, as there is no reason we would want all our integer values to access this method.

Also, there is no risk of miss using it and trying to convert a value of type Fahrenheit into the same type, as Fahrenheit types won’t have access to this method.

Awesome!

That’s all for today! 😄 I am fully aware it has been a different post than usual, more experimental maybe, but I hope you have enjoyed it.

It is really important to bear in mind the things we will be able to achieve when Dart matures a bit more; and specially I would like to encourage everybody to bring your own ideas onto the table.

Let me know your thoughts in the comments section below!

--

--

Sergio Fraile
Flutter Community

Mobile developer 📱 @ Workday | All things mobile (iOS, Android and Flutter) + ML | GDG Cloud Dublin organizer