2011-11-13 3 views
16

Considerate questo codice:Perché il limite minimo di java.lang.Integer e java.lang.Double è inferito come un tipo aciclico?

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

Il tipo derivato per foo è:

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

Quindi, in pratica il compilatore loop sui limiti e interrompe dopo il terzo ricorsione.

Perché il seguente non è sufficiente?

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

risposta

8

Non una risposta, ma alcuni indizi che utilizzano implicitamente nel REPL. Il compilatore non pensa che i tipi siano gli stessi. Il tipo derivato è più specifico:

// 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] 

Controllo ho fatto il tipo alias destra:

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 

tipi non sono la stessa:

implicitly[Soc =:= Inferred] // error 

tuo tipo è un tipo eccellente del tipo presunto:

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

Quindi, secondo il compilatore, è venuto fuori un tipo più specifico - che sarebbe la cosa giusta da fare. Si noti che il caso d'uso può essere ri-creato in questo modo:

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 

Quindi mi chiedo se siamo in grado di mettere una classe che è un DI_SOC ma non un DI, che illustrano DI e DI_SOC non sono gli stessi tipi e il tuo tipo non è il limite superiore.

Ok, dopo essere usciti dal computer per un po 'e poi riprovare. Ecco una classe che è un DI_SOC ma non un DI:

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

Applicato al caso uso originale:

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 

Pertanto, i tipi Soc e Inferred sono non stesso e Ax dimostra che Number with Comparable[_ >: Double with Integer <: Number] è non il limite minimo superiore ...

In altre parole, c'è spazio tra Double with Integer <: ? <: Number ma non molto tra Double with Integer <: ? <: Number with Comparable[_ >: Double with Integer <: Number]

Problemi correlati