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?

Answers


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 }

In addition to what has been said about implicit classes above, starting from Scala 2.10, you will be able to use value classes to avoid creating an intermediate object.

Essentially, you just have to make VectorMath above extend AnyVal. If you don't use the VectorMath object as a return value of a method, and instead just invoke VectorMath operations, no object for VectorMath will be allocated at runtime.


Note: This can lead to very unreadable code.

You could use implicit conversions and create some sort of wrapper class around Vector3f (like the Scala standard library itself with several Java classes, such as the Java collections see here.

// Somewhere, for example in a package object
implicit def wrapVector3f (v: Vector3f) = new Vector3fWrapper ( v );

class Vector3fWrapper (v: Vector3f) {
    // Use the Vector3f object internally here
    // You can now delegate all methods to the underlying Vector3f object
    // For example:
    def * (v: Vector3f) = {
        // ...
    }

    // or:
    def * (f: Float) = {
        // ...
    }
}

Everyone has already pointed out that you can implicitly add the operations to the Float on the left hand side, just wanted to point out you can make a right associative operator by putting a colon on the end of it.

class Vector3f(…) {
  …
  def *:(f: Float) = …
}

var v = new Vector3f(1,2,3);
var u = 1.2f *: v; //this works without any implicit magic or boxing overhead

it requires a small syntactic penalty, but is another option.


Need Your Help

Windows Azure - Framework Specs?

.net azure cloud

I'm playing around with a test project in Visual Studio 2010 and tried to publish it to Azure, but it was rejected as, out-of-the-box, VS2010 defaults to using .Net Framework 4.0 and Azure currentl...

How can I efficently pad an RGB numpy array with the median of the image?

python numpy image-processing

I have RGB images which have already been rescaled so that the longer edge becomes 256 pixels, now I want to pad the border with the median RGB values of that image so the resulting image is always