2011-11-13 9 views
16

consideran este código:¿Por qué se infiere el límite superior mínimo de java.lang.Integer y java.lang.Double como un tipo acíclico?

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

El tipo inferido para foo es:

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

Así que, básicamente, el compilador bucles sobre los límites y aborta después de la tercera recursividad.

¿Por qué no es suficiente con lo siguiente?

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

Respuesta

8

No es una respuesta, pero algunas pistas utilizando implícitamente en el REPL. El compilador no cree que los tipos sean iguales. El tipo inferido es más específico:

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

Comprobación de que hice las de tipo alias derecha:

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 

tipos no son los mismos:

implicitly[Soc =:= Inferred] // error 

Su tipo es un tipo súper de la tipo inferido:

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

De acuerdo con el compilador, surgió un tipo más específico, que sería lo correcto. Tenga en cuenta que el caso de uso puede ser re-creado de esta manera:

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 

Por eso me pregunto si podemos diseñar una clase que es una DI_SOC pero no un DI, que ilustran DI y DI_SOC no son los mismos tipos y su tipo no es el límite superior.

Ok, después de salir de la computadora un poco y luego volver a intentarlo. Aquí es una clase que es un DI_SOC pero no un DI:

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

Aplicado al caso de uso original:

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 

Por lo tanto, los tipos Soc y Inferred son no la misma y Ax demuestra que Number with Comparable[_ >: Double with Integer <: Number] es no el límite superior mínimo ...

En otras palabras, hay un espacio entre Double with Integer <: ? <: Number pero no mucho entre Double with Integer <: ? <: Number with Comparable[_ >: Double with Integer <: Number]

Cuestiones relacionadas