using Scala 2.10.1 Value Types in Java

2020-04-03 07:46发布

问题:

I am updating my 2.9.* project to 2.10. I have several classes for fundamental types (angles, lengths, etc) that seem like they are perfect candidates for value types. Unfortunately, my Java code that uses these types is not compiling, and I can't figure out why. I have simplified it down to a very simple set of code. Any suggestions would be much appreciated.

Angle class Definition (scala)

package com.example.units

class Angle(val radians : Double) extends AnyVal
{
  def degrees = radians * 180.0 / math.Pi
}

object Angle
{
  val Zero = new Angle(0)
}

Angle Test Case (painfully written in Java)

package com.example.units;

import junit.framework.Assert;
import org.junit.Test;

public class AngleTest
{
    @Test
    public static void TestZero()
    {
        Angle a = Angle.Zero();
        Assert.assertEquals(a.degrees(), 0, 1E-9);

    }

}

When I compile, I get this error:

AngleTest.java:19 incompatible types
found :double
required: com.example.units.Angle
Angle a = Angle.Zero();

            ^

It looks to me as if Angle.Zero is being returned as a double, not an Angle. I tried adding box/unbox methods, but continue to receive the same error. Again, any help would be greatly appreciated.

回答1:

Scala compiler turns value classes into their unboxed type, which eliminates their cost for runtime. Inspecting the compiled class file for Angle, you'll see:

public static double Zero();

So from Java's point of view, Angle.Zero returns a double; it's not aware of the semantics of Scala's value classes.

Angle's own methods, such as degrees, get compiled into a) a static extension method that takes in the unboxed value (double) b) an instance method:

public static double degrees$extension(double);
public double degrees();

Which means the latter can still be called on an instance of Angle in Java:

Angle a = new Angle(0);
Assert.assertEquals(a.degrees(), 0, 1E-9);