2010-01-22 10 views
6

Dadas las siguientes características y clase. ¿Por qué esta compilación? ¿Se puede usar esto realmente para algo?Clases concretas con miembros de tipo abstracto

trait Container { 
    type A 
} 

trait AnotherContainer[B]{ 
    def x(b : B) : B 
} 

trait Mixed extends Container with AnotherContainer[Container#A] 

class Impl extends Mixed{ 
    def x(a : Container#A) = a 
} 

new Impl().x _ 

scala> new Impl().x _ 
res0: (Container#A) => Container#A = <function> 

Actualización:

class Baz { type T; } 

es en realidad una característica, pero no pude encontrar la motivación para ello: #1753.

+0

Parece un error para mí. –

+0

¿Por qué? B en el caso de AnotherContainer en Mixed es A, por lo que la firma de x es consistente entre AnotherContainer.x e Impl.x. ¿O me estoy perdiendo algo? –

+0

@Randall Bueno, el 'tipo A' es abstracto, y no veo que se concrete en ninguna parte. Así que esperaría que 'Impl' no compilara, devolviendo un error de" necesita ser abstracto ". –

Respuesta

2

Parece inofensivo si no sirve para nada. El tipo que x quiere no existe, por lo que no puede pasarlo al método. Si la inutilidad inofensiva debería ser un error en tiempo de compilación es una cuestión de gusto, supongo.

Si nos fijamos en lo que realmente hace x, decompila así:

public java.lang.Object x(java.lang.Object); 
    Code: 
    0: aload_1 
    1: areturn 

que es exactamente lo que el método de la identidad debe hacer (carga el argumento independientemente del tipo, devolverlo). Se puede escribir algo equivalente con mucho menos código:

trait AbstractType { type T } 
class Useless extends AbstractType { def identity(t: AbstractType#T) = t } 

Excepto nada tiene tipo AbstractType # T, lo que de nuevo tenemos la inutilidad.

A menos que me esté perdiendo algo.

3

En su ejemplo, el compilador agrega los límites de tipo predeterminados de >: Nothing <: Any. El segundo ejemplo a continuación muestra un caso en el que se puede usar un tipo abstracto (si no es útil).

scala> trait T { type A >: Nothing <: Any } 
defined trait T 

scala> 1: T#A 
<console>:6: error: type mismatch; 
found : Int(1) 
required: T#A 
     1: T#A 
    ^

scala> trait T { type A >: Int <: Int } 
defined trait T 

scala> 1: T#A       
res6: T#A = 1 

scala> "": T#A 
<console>:6: error: type mismatch; 
found : java.lang.String("") 
required: T#A 
     "": T#A 
    ^
+1

'rasgo T {tipo A>: Int <: Int}' es simplemente una forma complicada de definir 'rasgo T {tipo A = Int}' el resultado es el mismo. –

+0

Sí, ese fue el punto que intenté transmitir. – retronym

Cuestiones relacionadas