Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the least upper bound of java.lang.Integer and java.lang.Double inferred as a acyclic type?

Consider this code:

val foo = if(true) 
            new java.lang.Double(4) 
          else
            new java.lang.Integer(4)

The inferred type for foo is:

Number with Comparable[_ >: Double with Integer <: Number with 
  Comparable[_ >: Double with Integer <: Number]]

So basically the compiler loops on the bounds and aborts after the third recursion.

Why isn't the following enough?

Number with Comparable[_ >: Double with Integer <: Number]
like image 514
soc Avatar asked Nov 13 '11 02:11

soc


1 Answers

Not an answer but some clues using implicitly in the REPL. The compiler doesn't think the types are the same. The inferred type is more specific:

// some type aliases to make reading easier
type Dx = java.lang.Double
type Ix = java.lang.Integer

// the type the compiler came up with:
type Inferred = Number with Comparable[
  _ >: Dx with Ix <: Number with Comparable[_ >: Dx with Ix <: Number]]

// your type:
type Soc = Number with Comparable[_ >: Dx with Ix <: Number]

Checking I did the type aliases right:

val d = new java.lang.Double(4)
val i = new java.lang.Integer(4)
val foo: Soc = if (true) d else i
// foo: Soc = 4.0
val foo: Inferred = if (true) d else i
// foo: Inferred = 4.0

Types are not the same:

implicitly[Soc =:= Inferred] // error

Your type is a super type of the inferred type:

implicitly[Inferred <:< Soc] // ok
implicitly[Soc <:< Inferred] // error

So according to the compiler, it came up with a more specific type - which would be the right thing to do. Note that the use case can be re-created like this:

class N                     // like java.lang.Number

trait C[T]                  // like Comparable

class I extends N with C[I] // like java.lang.Integer
class D extends N with C[D] // like java.lang.Double

type DI = N with C[_ >: D with I <: N with C[_ >: D with I <: N]]
// DI is like the type inferred

type DI_SOC = N with C[_ >: D with I <: N] // your type

val foo: DI = if (true) new D else new I     // ok
val foo: DI_SOC = if (true) new D else new I // ok

implicitly[DI =:= DI_SOC] // error
implicitly[DI <:< DI_SOC] // DI_SOC super type of DI
implicitly[DI_SOC <:< DI] // error

So I wonder if we can craft a class that is a DI_SOC but not a DI, which would illustrate DI and DI_SOC are not the same types and your type is not the least upper bound.

Ok, after stepping out for the computer for a bit and then trying again. Here is a class that is a DI_SOC but not a DI:

class A extends N with C[N]
implicitly[A <:< DI_SOC] // ok
implicitly[A <:< DI]     // error

Applied to the original use case:

class Ax extends Number with Comparable[Number] {
  def doubleValue() = 0d
  def floatValue() = 0f
  def intValue() = 0
  def longValue() = 0L
  def compareTo(n: Number) = 0
}

implicitly[Ax <:< Soc]      // ok
implicitly[Ax <:< Inferred] // error

Therefore, the types Soc and Inferred are not the same and Ax proves that Number with Comparable[_ >: Double with Integer <: Number] is not the least upper bound...

In other words, there is some room between Double with Integer <: ? <: Number but not much between Double with Integer <: ? <: Number with Comparable[_ >: Double with Integer <: Number]

like image 157
huynhjl Avatar answered Dec 07 '22 05:12

huynhjl