Saturday, October 5, 2013

JavaScript Operator Overloading


Javascript has no support for operator overloading. Axel Rauschmayer created a clever hack to provide "fake" operator overloading, but this has several drawbacks. Juho Vepsäläinen created an example solution using JSShaper, that parses and modifies the JavaScript AST, see his blog post and commit. Too bad Juho stopped working on his project two years ago, and only providing support for: +, -, /, *

I also had a look at CoffeeScript and TypeScript, and was very surprised to see that neither one of these has support for operator overloading. CoffeeScript could have added this feature, but would have needed static type checking in order to do it selectively, see this issue. TypeScript can easily support operator overloading, last year Ursuletzu created a fork that adds this feature, but his work was rejected by Jonathan Turner, see this heated thread.

Is it time to give up on operator overloading and JavaScript? Not yet, about a week ago I blogged about adding support for __getattr__ to PythonScript. My approach was similar to Juho Vepsäläinen's, but instead of changing the JavaScript AST, I modified the Python AST in the first stage of the PythonScript compiler. Python provides a well developed system for operator overloading that can be fully leveraged using this technique. It may sound ironic, the best solution for operator overloading in JavaScript is to write your code in Python. In my recent commits [1] [2], to the PythonScript development branch, I have added support for overloading the following operators:

  • +
  • -
  • *
  • /
  • %
  • <<
  • >>
  • &
  • ^
  • |
  • +=
  • -=
  • *=
  • /=
  • %=
  • <<=
  • >>=
  • &=
  • ^=
  • |=

THREE.Vector3

I have fully wrapped the THREE.Vector3 class with smart methods that are able to detect if the right operand is a scalar or Vector3 type. The technique for checking the type of a JavaScript object at runtime is to inline a JavaScript expression into the the Python if statement. At first this seems strange, but is actually a very powerful feature of the PythonScript compiler. See below: JS("{}.toString.call(o) === '[object Object]'")

class Vector3:
 ... 

 def add(self, o):
  assert isinstance(o, Vector3)
  self.set( self.x+o.x, self.y+o.y, self.z+o.z )
  return self

 def addScalar(self, s):
  self.set( self.x+s, self.y+s, self.z+s )
  return self

 def __add__(self, o):
  if JS("{}.toString.call(o) === '[object Object]'"):
   assert isinstance(o, Vector3)
   return Vector3( self.x+o.x, self.y+o.y, self.z+o.z )
  else:
   return Vector3( self.x+o, self.y+o, self.z+o )

 def __iadd__(self, o):
  if JS("{}.toString.call(o) === '[object Object]'"):
   self.add( o )
  else:
   self.addScalar( o )

1 comment:

  1. Thanks for splitting your comprehension with us. It’s really useful to me & I hope it helps the people who in need of this vital information. Python Training in Chennai

    ReplyDelete