Search code examples
javascalaoverloadingoperator-keywordfinal

Add Scala operators to final Java class


I am using the jMonkeyEngine (Java Game Engine) in Scala, which works out pretty well so far, but now I am asking myself whether there is an elegant way of overloading operators for the Vector3f (and similar) classes. My first idea was to inherit from Vector3f and overload the operators, but Vector3f is final, so that is not an option. Next I thought maybe I could have a singleton/scala object with static methods that operate on Vector3f, like below, but that does not work either:

object VectorMath {
    def *(factor: Float, vector: Vector3f) = vector.mult(factor)
}

//and then somewhere
import VectorMath._
var v = new Vector3f(1,2,3);
var u = 1.2f * v; //this does not work, because Float does not have * overloaded for Vector3f
var u = VectorMath.*(1.2f, v); //this does work, but defeats the purpose

So all I can think of now is to wrap the Vector3f in a new Scala class and delegate the operator calls to the appropriate Java methods. This has, however, three downsides:

  1. I will have to do to a lot of back and forth conversions (a toVector3f and a fromVector3f method or something like that).
  2. This problem becomes even worse when I have arrays of Vector3f/ScalaVectors. Since the classes are not related (except by composition), I would have to manually cast every element of the array every time I call a method in jME.
  3. Even then I know of no way to overload an operator for my new ScalaVector class in such a way that I could have the factor in front, i.e. 1.2f * v.

My question: Can someone think of a way to make this more natural/elegant? How do you tackle similar problems? Or is there maybe a Scala syntax that I don know of to do these kinds of things? In C++ I would make a global operator that takes float and Vector3f as arguments and possibly friend it. Whats the Scala way to do this, or is that simply not possible?


Solution

  • Or is there maybe a Scala syntax that I don't know of to do these kinds of things?

    Yeah, there are implicits:

    class VectorMath(f: Float) { def * (v: Vector3f) = v mult f }
    implicit def VectorMath(f: Float) = new VectorMath(f)
    
    val v = new Vector3f(1,2,3)
    1.2F * v
    // treated as: VectorMath(1.2F).*(v)
    

    Since Scala 2.10 the implicit conversion can also be written as:

    implicit class VectorMath(f: Float) { def * (v: Vector3f) = v mult f }
    

    Since 2.10 there are also value classes which are optimized by the compiler to get better performance:

    implicit class VectorMath(val f: Float) extends AnyVal { def * (v: Vector3f) = v mult f }