Home > other >  Overload Operator for Built-in Type in Dart
Overload Operator for Built-in Type in Dart

Time:05-24

Consider the following Dart code:

class Vec2 {
  num x, y;
  Vec2(this.x, this.y);
  Vec2 operator*(num rhs) => Vec2(x * rhs, y * rhs);
  String toString() => "<$x, $y>";
}

void main() => print(Vec2(1, 2) * 3);

The output is as expected:

<3, 6>

However, this only works when the left-hand side of the expression is a Vec2 and the right-hand side is a num. In this case, I want the multiplication operator to be commutative, so I write the following extension:

extension Vec2Util on num {
  Vec2 operator*(Vec2 rhs) => Vec2(rhs.x * this, rhs.y * this);
}

One might naturally expect the following code to produce identical output to the first snippet:

void main() {
  num x = 3;
  print("${x * Vec2(1, 2)}");
}

However, the compiler is instead reporting that The argument type 'Vec2' can't be assigned to the parameter type 'num'. It looks as though the compiler is resolving the multiplication to num operator*(num rhs) in this case and then complaining that my Vec2 can't be passed in as a num operand. Why does the compiler apparently disregard my extension? What is the correct way to create custom commutative operators like this?

CodePudding user response:

You cannot do what you want.

Dart user-definable binary operators are all methods on the first operand. Doing e1 e2 is kind-of like doing e1. (e2) where is the name of the method, except you can't normally call a method .

In order to be able to do 3 * vector, you need the method to be on 3.

You can't add methods to other people's classes, not without fiddling with their source code, and int is a system class so even that is not possible.

You cannot use extension methods because extension methods do not apply when the receiver type already has an instance method with the same name. And int defines all the operators. (It's like, and definitely not coincidentally, that the user-definable operators were chosen from exactly what int needs. That's not new in Dart, the operators go back to C and Java.)

So, you can define an extension method on int, but you can't call it anyway, not without an override:

extension MyInt on int {
  Vector operator *(Vector other) => other.scalerMultiplication(this);
}
... MyInt(3) * vector ...

That's more complication than just swapping the operands.

  • Related