2013-08-07 11 views
5

sto cercando di capire il motivo per cui il compilatore Scala non può dedurre la seguente limitazione su un tipo dipendente dal percorso:Scala - Bassa inferenza rilegato in tipi dipendenti dal percorso

trait MyTrait 
class MyTraitImpl extends MyTrait 
trait MyTrait2[A <: MyTrait] { 
    type MyTraitType = A 
} 
class MyTrait2Impl[A <: MyTrait] extends MyTrait2[A] 

val obj: MyTrait2[_] = new MyTrait2Impl[MyTraitImpl] 

def myMethod[A <: MyTrait](t2: MyTrait2[A]) = println("Hi!") 

myMethod[obj.MyTraitType](obj) 
// <console>:14: error: type arguments [obj.MyTraitType] do not conform to method myMethod's type parameter bounds [A <: MyTrait] 
//    myMethod[obj.MyTraitType](obj) 

Per me, intuitivamente, MyTraitType non può essere nient'altro che una sottoclasse di MyTrait, poiché il limite è a destra su A in MyTrait2. Se c'è, puoi darmi un esempio o indicarmi dove questo snippet di codice è sbagliato?

Se questa è una limitazione del compilatore Scala, qualcuno può mostrarmi un modo per ottenere ciò utilizzando il sistema di tipi? Si noti che:

  • non ho un oggetto MyTrait, né myMethod ricevere uno;
  • Non ho bisogno di myMethod per conoscere il tipo di calcestruzzo A; tutto ciò che deve sapere è che A è un sottotipo di MyTrait e che t2 è parametrizzato su A;
  • Il trattino di sottolineatura in obj è intenzionale; dove chiamo myMethod, non conosco il tipo concreto di A (altrimenti non sarebbe un problema);
  • Preferisco le soluzioni in cui non è necessario modificare myMethod.

risposta

3

Si dovrebbe solo utilizzare vincoli membro tipo, invece di limiti sul tipo di parametro in MyTrait2 dichiarazione:

trait MyTrait 
class MyTraitImpl extends MyTrait 
trait MyTrait2 { // Remove [A <: MyTrait] 
    type MyTraitType <: MyTrait // add <: MyTrait 
} 
class MyTrait2Impl[A <: MyTrait] extends MyTrait2 { type MyTraitType = A } 

val obj: MyTrait2 = new MyTrait2Impl[MyTraitImpl] 

def myMethod[A <: MyTrait](t2: MyTrait2{ type MyTraitType = A }) = println("Hi!") 

myMethod[obj.MyTraitType](obj) 

si otterrà un errore di compilazione sul tipo sbagliato, proprio come previsto:

scala> val otherObj: MyTrait2 = new MyTrait2Impl[MyTraitImpl] 
otherObj: MyTrait2 = [email protected] 

scala> myMethod[obj.MyTraitType](otherObj) 
<console>:15: error: type mismatch; 
found : otherObj.type (with underlying type MyTrait2) 
required: MyTrait2{type MyTraitType = obj.MyTraitType} 
       myMethod[obj.MyTraitType](otherObj) 
             ^

prova funziona con List[MyTrait2]:

scala> for { 
    | obj <- List[MyTrait2](
    |   new MyTrait2Impl[MyTraitImpl], 
    |   new MyTrait2Impl[MyTraitImpl] 
    |   ) 
    | } myMethod[obj.MyTraitType](obj) 
Hi! 
Hi! 
+0

In questo modo funziona davvero, ma è una specie di soluzione alternativa per il trattino basso nella domanda originale.Nella tua soluzione, la chiamata funziona perché il compilatore conosce il tipo concreto 'A' in' obj', mentre nel mio esempio l'ho soppresso esplicitamente. Immaginiamo ora di avere un 'List [MyTrait2]' e voglio chiamare 'myMethod' con uno degli elementi; non funzionerà con entrambe le soluzioni. Tuttavia, nella mia mente, penso che dovrebbe, dato che ci sono limiti concreti ('<: MyTrait') su quali tipi possono' A' prendere. –

+0

@RuiGoncalves: la mia soluzione funziona con 'List [MyTrait2]' bene. – senia

+0

@ RuiGonçalves: ho aggiunto la prova alla mia risposta, vedere l'aggiornamento. – senia

1

Se davvero si vuole mantenere il parametro generico (io sono d'accordo, tipi astratti sarebbero più bello in questo caso), è possibile effettuare le seguenti operazioni:

limitare il tipo jolly di obj:

val obj: MyTrait2[_ <: MyTrait] = new MyTrait2Impl[MyTraitImpl] 

Chiamata myMethod senza parametri di tipo e lasciare che la figura del compilatore fuori:

myMethod(obj) 

Questo non è altro che aiutare il compilatore fuori un po 'con il tipo di inferenza. Il tuo ragionamento su MyTrait2#MyTraitType ovviamente è corretto.

Un'altra soluzione (andando nella stessa categoria) è in calo il tipo di obj:

val obj = new MyTrait2Impl[MyTraitImpl] 

Ma, naturalmente, che potrebbe non applicarsi nel vostro caso d'uso reale.

Problemi correlati