Enhance your classes with operator overloading in Dart

Fré Dumazy
3 min readMay 13, 2019

--

As a modern programming language, Dart has a lot of niceties and syntactic sugar for developers to use. Recently, I’ve started to use operator overloading quite often to add easily readable functionality to the classes in my model.

Operator overloading

For those who haven’t heard about this, let me explain what this actually is.
Operator overloading gives you the ability to add custom implementations to a certain set of operators in your classes. These operators can be:

  • Arithmetic operators like + - * etc.
  • Equality operators like == and !=
  • Relational operators, > >= < and <=
  • and many more

This language feature can also be found in other languages like Kotlin, Groovy, C++, and so on.

For example, we have an application with two classes, Person and Family. By overloading the plus operator we would be able to have the following:

Family family = new Person() + new Person();

To achieve this we should have the following classes:

class Person {
Family operator +(Person other) {
return Family([this, other]);
}
}
class Family {
final List<Person> people;
Family(this.people);
}

Let’s have a closer look at the code that overloads the operator.

Family operator +(Person other) {
return Family([this, other]);
}

We use the reserved keyword operator and the specific operator we want to overload, the plus operator in this case: +
As a return type we define Family. In the function body we simply create a Family object by passing a List literal, with both Person objects.

The order of the operands goes from left to right, meaning that this is the left Person and other is the right one.

Another example

Maybe you might be thinking, is this useful? Well, the family example isn’t really the best use case but I was able to use it in a helpful way when I was making a Flutter app to keep track of my utilities consumption at the house.

class MeterReading {
final double electricity;
final double gas;
final double water;
MeterReading({this.electricity, this.gas, this.water}); Consumption operator -(MeterReading other) => Consumption(
electricity: (electricity - other.electricity).abs(),
gas: (gas - other.gas).abs(),
water: (water - other.water).abs()
);
}

By overloading the minus operator, I was able to use this syntactic sugar in my calculation functions:

Consumption consumption = reading - previousReading;

Another one I needed to use was a multiplier. If a consumption was measured between March 10 and April 10, I would have to multiply the consumption by approximately 0.67 to get the partial consumption of March. Afterwards I could add that to the consumption of the first 10 days of March, by overloading the plus operator.

// Consumption.dartConsumption operator *(double multiplier) => Consumption(
electricity: electricity * multiplier,
gas: gas * multiplier,
water: water * multiplier,
);
Consumption operator +(Consumption other) => Consumption(
electricity: electricity + other?.electricity,
gas: gas + other?.gas,
water: water + other?.water,
);

Order of operators

During development of this tool, I suddenly got unexpected results.

Consumption one = Consumption(electricity: 15, gas: 3, water: 9);
Consumption two = Consumption(electricity: 5, gas: 7, water: 11);
Consumption result = one + two * 0.5;
print("Result is $result");

I was expecting to get the following result:
> Result is electricity: 10.0, gas: 5.0, water: 10.0
Instead I got:
> Result is electricity: 17.5, gas: 6.5, water: 14.5.

The reason for this is that these operators still have a specific operator precedence. This caused the code above to first execute two * 0.5 and then execute the plus operation. Adding parentheses fixed this problem.

Consumption result = (one + two) * 0.5

More operators

Besides the ones I’ve showed, Dart has a lot more operators that can be overriden for custom implementations.

Two interesting ones worth mentioning is the list access operator []and the function invocation operator () by implementing call(). These can help to add more syntactic sugar to your model or even create a domain specific language in Dart.

Check out more about operator overloading in Dart in the documentation and let me know in which way you are using them! :-)

--

--