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-variant 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
Basepromises to returnAform a certain method, then a subclassDerived <: Baserespects the Liskov substitution principle if it returnsAor any subclassB <: A. Certainly, ifBigInt#underlyingreturns aBigInteger, this is no problem for clients ofScalaNumber, who may only hope for a plainObject.