开发者

How does the implementation of ScalaNumber work regarding underlying?

scala.math.ScalaNumber is a Java file which looks like this:

public abstract class ScalaNumber extends java.lang.Number {
  protected abstract boolean isWhole();
  public abstract Object underlying();
}

And scala.math.BigDecimal implements it with:

class BigDecimal(val bigDecimal: BigDec, val mc: MathContext)
extends ScalaNumber with ScalaNumericConversions with Serializable {
  ...
  def underlying = bigDecimal
}

as well as scala.math.BigInt:

class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable {
  ...
  def underlying = bigInteger
}

Confusingly, underlying is of type java.math.BigDecimal/java.math.BigInt instead of Object.

Do I miss something pretty obvious or is there something special-cased here?

EDIT: Of course I missed something obvious ... You're all right. Co-vari开发者_JAVA技巧ant return types. Thanks!


It is simply a covariant return type, which is allowed both in Scala and Java.

The rationale behind it is: if a class Base promises to return A form a certain method, then a subclass Derived <: Base respects the Liskov substitution principle if it returns A or any subclass B <: A. Certainly, if BigInt#underlying returns a BigInteger, this is no problem for clients of ScalaNumber, who may only hope for a plain Object.


In both Java and Scala method return types can be covariant when overriding. That is to say if you override a method you can make its return type be a subtype of the overriden method's return type.

scala> class Foo { def method : Object = "foo" }
defined class Foo

scala> class Bar extends Foo {override def method : String = "bar" }
defined class Bar

scala> (new Foo).method
res0: java.lang.Object = foo

scala> (new Bar).method
res1: String = bar

scala> ((new Bar) : Foo).method
res2: java.lang.Object = bar
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜