Dart: Extend Class Functionality Using Extension

Mario Gunawan
3 min readFeb 2, 2023

--

Flutter Extension is a way to add extra function(s) into a module. To imagine its possibilities, let’s see how it works first. Let’s create an empty project and create an empty dart file (for simplicity sake, let’s call it main.dart from now on) and put this lines of code:

void main() {
String text = "Hello i am a text";

print(text.firstChar);
}

When you try running it (dart ./main.dart), you will run into an error

For other languages, we’re usually stuck with creating another function. For example, if we play in the java world, we can create a utils.dart class and create a util class that has to do with string transformation.

// illustration for context using dart language
class Utils {
final String _text;

Utils(this._text);

String get firstChar => this.text[0];
}

Or, if we live in the c world, we’d be creating a utility function.

String getFirstChar(String text) => text[0];

Thankfully, in dart, we can create what we’d call an extension of the class that’s already there. Let’s use String for an example:

extension Something on String {
String get firstChar => this[0];
}

And using the extension, we can now call the firstChar method in our code without error:

void main() {
String text = "Hello i am a text";

print(text.firstChar); // now the method is recognized
}

If you are working in a different file, then you need to import the extension first to use the extended method:

import 'main.dart'; // import main.dart that have the extension

String getAvatarCharacter(String str) {
return str.firstChar; // we can use this now
}

We can also extend an already existing class. This is useful if you wanted to extend a library’s capability even further without creating useless class/function(s):

extension FakerExtension on Faker {
int get diceRoll => this.randomGenerator.integer(
6,
min: 0,
);
}

We can even create a new static variable for use in our extension:

extension FakerExtension on Faker {
static const int diceSides = 6;

int get diceRoll => this.randomGenerator.integer(
diceSides,
min: 0,
);
}

But unlike methods, those static methods cannot be accessed in our code:

Faker.diceSides // this will produce an error

Like other constructs extension names cannot be duplicates, so be mindful when naming them:

extension Something on String {
String get firstChar => this[0];
}

extension Something on String {
String get lastChar => this[length -1];
}

You might’ve noticed that you can also use this keyword as well in the extension.

One unique thing about extensions is they can also use other methods within the extension but they cannot use methods in a different extension:

extension Something on String {
String get firstChar => this[0];
bool get isFirstCharA => this.firstChar == "A"; // this is fine
}

extension SomethingTwo on String
bool get isFirstCharB => this.firstChar == "B"; // this produces error
}

I haven’t found any way to extend or connect one extension with the other, using each other’s methods. But I think that’s for the best because it can introduce messy code if we create too many extensions.

There are many use cases for extension. For example, base classes like string or int that have limited capabilities will be able to do more without creating util classes/functions. Also, like the examples above, we can extend our favorite library’s functionality to suit our needs.

But, be careful when using it because the problem that extension solves might also be solved with another cleaner approach that requires less meddling with the inner workings of an already established class.

That’s all for today, thanks for reading & see ya!

--

--

Mario Gunawan

I'm a mobile / web developer. I'm mostly writing articles about software development.