PythonJS now translates operator overloading from Python to the Dart backend, see my commit here. Dart supports all the same operators as Python, except for in-place operators. In-place operators are very useful, I am curious why the Dart developers have left this feature out?

Even if this feature is missing in Dart, it can still be forced to work when PythonJS translates to Dart code, by inlining a special if/else for each in-place assignment. Example **x += y**

*if x is a Number or String: then use +=: else use x.__iadd__(y)*

The Dart2js compiler is smart enough to determine the type of **x** at compile time, and optimize the if/else away. This opens the door for doing more dumb tricks from PythonJS that get optimized away by Dart2js.

### Python Input

class Vector3:
def __init__(self, x=0, y=0, z=0 ):
self._x = x
self._y = y
self._z = z
def set(self, x,y,z):
self._x = x
self._y = y
self._z = z
@property
def x(self):
return self._x
@x.setter
def x(self, value):
print 'x setter', value
self._x = value
@property
def y(self):
return self._y
@y.setter
def y(self, value):
print 'y setter', value
self._y = value
@property
def z(self):
return self._z
@z.setter
def z(self, value):
print 'z setter', value
self._z = value
def add(self, other):
self.set( self.x+other.x, self.y+other.y, self.z+other.z )
return self
def __add__(self, other):
if instanceof(other, Number):
return Vector3( self.x+other, self.y+other, self.z+other )
else:
return Vector3( self.x+other.x, self.y+other.y, self.z+other.z )
def __iadd__(self, other):
if instanceof(other, Number):
self.addScalar( other )
else:
self.add( other )
def addScalar(self, s):
self.set( self.x+s, self.y+s, self.z+s )
return self
def sub(self, other):
self.set( self.x-other.x, self.y-other.y, self.z-other.z )
return self
def __sub__(self, other):
if instanceof(other, Number):
return Vector3( self.x-other, self.y-other, self.z-other )
else:
return Vector3( self.x-other.x, self.y-other.y, self.z-other.z )
def __isub__(self, other):
if instanceof(other, Number):
self.set( self.x-other, self.y-other, self.z-other )
else:
self.sub( other )
def multiply(self, other):
self.set( self.x*other.x, self.y*other.y, self.z*other.z )
return self
def __mul__(self, other):
if instanceof(other, Number):
return Vector3( self.x*other, self.y*other, self.z*other )
else:
return Vector3( self.x*other.x, self.y*other.y, self.z*other.z )
def __imul__(self, other):
if instanceof(other, Number):
self.multiplyScalar( other )
else:
self.multiply( other )
def multiplyScalar(self, s):
self.set( self.x*s, self.y*s, self.z*s )
return self
def divide(self, other):
self.set( self.x/other.x, self.y/other.y, self.z/other.z )
return self
def divideScalar(self, s):
self.set( self.x/s, self.y/s, self.z/s )
return self
def __div__(self, other):
if instanceof(other, Number):
return Vector3( self.x/other, self.y/other, self.z/other )
else:
return Vector3( self.x/other.x, self.y/other.y, self.z/other.z )
def __idiv__(self, other):
if instanceof(other, Number):
self.divideScalar( other )
else:
self.divide( other )
def show_vec(v):
print '-------------'
print v.x
print v.y
print v.z
def main():
n = 1
n += 2
print n
v1 = Vector3(1, 2, 3)
v2 = Vector3(10, 0, 10)
print v1, v2
print 'testing +'
a = v1 + v2
show_vec(a)
print 'testing +='
a += 2.5
show_vec(a)
a += v1
show_vec(a)
print 'testing -='
a -= v1
show_vec(a)
a -= 100
show_vec(a)
print 'testing *'
b = v1 * v2
show_vec(b)
print 'testing *='
b *= 10.0
show_vec(b)
b *= v2
show_vec(b)
print 'testing setters'
b.x = 1
b.y = 2
b.z = 3

### Dart Output

class Vector3 {
var _z;
var _y;
var _x;
static void __init__(self, [x=0,y=0,z=0]) {
self._x = x;
self._y = y;
self._z = z;
}
Vector3(x,y,z) {Vector3.__init__(this,x,y,z);}
set(x,y,z) { return Vector3.__set(this,x,y,z); }
static __set(self, x, y, z) {
self._x = x;
self._y = y;
self._z = z;
}
get x {
return this._x;
}
set x(value) {
print(["x setter", value]);
this._x = value;
}
get y {
return this._y;
}
set y(value) {
print(["y setter", value]);
this._y = value;
}
get z {
return this._z;
}
set z(value) {
print(["z setter", value]);
this._z = value;
}
add(other) { return Vector3.__add(this,other); }
static __add(self, other) {
self.set((self.x + other.x), (self.y + other.y), (self.z + other.z));
return self;
}
operator +(other) { return Vector3.____add__(this,other); }
static ____add__(self, other) {
if (other is num) {
return new Vector3((self.x + other), (self.y + other), (self.z + other));
} else {
return new Vector3((self.x + other.x), (self.y + other.y), (self.z + other.z));
}
}
__iadd__(other) { return Vector3.____iadd__(this,other); }
static ____iadd__(self, other) {
if (other is num) {
self.addScalar(other);
} else {
self.add(other);
}
}
addScalar(s) { return Vector3.__addScalar(this,s); }
static __addScalar(self, s) {
self.set((self.x + s), (self.y + s), (self.z + s));
return self;
}
sub(other) { return Vector3.__sub(this,other); }
static __sub(self, other) {
self.set((self.x - other.x), (self.y - other.y), (self.z - other.z));
return self;
}
operator -(other) { return Vector3.____sub__(this,other); }
static ____sub__(self, other) {
if (other is num) {
return new Vector3((self.x - other), (self.y - other), (self.z - other));
} else {
return new Vector3((self.x - other.x), (self.y - other.y), (self.z - other.z));
}
}
__isub__(other) { return Vector3.____isub__(this,other); }
static ____isub__(self, other) {
if (other is num) {
self.set((self.x - other), (self.y - other), (self.z - other));
} else {
self.sub(other);
}
}
multiply(other) { return Vector3.__multiply(this,other); }
static __multiply(self, other) {
self.set((self.x * other.x), (self.y * other.y), (self.z * other.z));
return self;
}
operator *(other) { return Vector3.____mul__(this,other); }
static ____mul__(self, other) {
if (other is num) {
return new Vector3((self.x * other), (self.y * other), (self.z * other));
} else {
return new Vector3((self.x * other.x), (self.y * other.y), (self.z * other.z));
}
}
__imul__(other) { return Vector3.____imul__(this,other); }
static ____imul__(self, other) {
if (other is num) {
self.multiplyScalar(other);
} else {
self.multiply(other);
}
}
multiplyScalar(s) { return Vector3.__multiplyScalar(this,s); }
static __multiplyScalar(self, s) {
self.set((self.x * s), (self.y * s), (self.z * s));
return self;
}
divide(other) { return Vector3.__divide(this,other); }
static __divide(self, other) {
self.set((self.x / other.x), (self.y / other.y), (self.z / other.z));
return self;
}
divideScalar(s) { return Vector3.__divideScalar(this,s); }
static __divideScalar(self, s) {
self.set((self.x / s), (self.y / s), (self.z / s));
return self;
}
operator /(other) { return Vector3.____div__(this,other); }
static ____div__(self, other) {
if (other is num) {
return new Vector3((self.x / other), (self.y / other), (self.z / other));
} else {
return new Vector3((self.x / other.x), (self.y / other.y), (self.z / other.z));
}
}
__idiv__(other) { return Vector3.____idiv__(this,other); }
static ____idiv__(self, other) {
if (other is num) {
self.divideScalar(other);
} else {
self.divide(other);
}
}
}
show_vec(v) {
print("-------------");
print(v.x);
print(v.y);
print(v.z);
}
main() {
var a, v1, v2, b, n;
n = 1;
if (n is num || n is String) {
n += 2;
} else {
n.__iadd__(2);
}
print(n);
v1 = new Vector3(1, 2, 3);
v2 = new Vector3(10, 0, 10);
print([v1, v2]);
print("testing +");
a = (v1 + v2);
show_vec(a);
print("testing +=");
if (a is num || a is String) {
a += 2.5;
} else {
a.__iadd__(2.5);
}
show_vec(a);
if (a is num || a is String) {
a += v1;
} else {
a.__iadd__(v1);
}
show_vec(a);
print("testing -=");
if (a is num || a is String) {
a -= v1;
} else {
a.__isub__(v1);
}
show_vec(a);
if (a is num || a is String) {
a -= 100;
} else {
a.__isub__(100);
}
show_vec(a);
print("testing *");
b = (v1 * v2);
show_vec(b);
print("testing *=");
if (b is num || b is String) {
b *= 10.0;
} else {
b.__imul__(10.0);
}
show_vec(b);
if (b is num || b is String) {
b *= v2;
} else {
b.__imul__(v2);
}
show_vec(b);
print("testing setters");
b.x = 1;
b.y = 2;
b.z = 3;
}