2013-01-05 3 views
10

Stavo convertendo un codice da 2.9 a 2.10 e ho trovato un errore di compilazione imprevisto. Ecco la forma minima:comportamento flatMap cambiato in 2.10.0

In 2.9.2, questo funziona bene:

scala> List(1).flatMap(n => Set(1).collect { case w => w }) 
res0: List[Int] = List(1) 

In 2.10.0, otteniamo un errore:

scala> List(1).flatMap(n => Set(1).collect { case w => w }) 
<console>:8: error: no type parameters for method flatMap: (f: Int => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[List[Int],B,That])That exist so that it can be applied to arguments (Int => scala.collection.immutable.Set[_ <: Int]) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : Int => scala.collection.immutable.Set[_ <: Int] 
required: Int => scala.collection.GenTraversableOnce[?B] 
       List(1).flatMap(n => Set(1).collect { case w => w }) 
        ^
<console>:8: error: type mismatch; 
found : Int => scala.collection.immutable.Set[_ <: Int] 
required: Int => scala.collection.GenTraversableOnce[B] 
       List(1).flatMap(n => Set(1).collect { case w => w }) 
           ^
<console>:8: error: Cannot construct a collection of type That with elements of type B based on a collection of type List[Int]. 
       List(1).flatMap(n => Set(1).collect { case w => w }) 
          ^

Ma funziona bene in 2.10.0 se mi rivolgo in modo esplicito il risultato interno in un List o specificare i tipi generici di flatmap esplicitamente:

scala> List(1).flatMap(n => Set(1).collect { case w => w }.toList) 
res1: List[Int] = List(1) 
scala> List(1).flatMap[Int, List[Int]](n => Set(1).collect { case w => w }) 
res2: List[Int] = List(1) 

Qualcuno può spiegarmi quale sia stato il cambiamento a 2.10 che causa l'inferenza di tipo per fallire qui quando non era in 2.9?

EDIT:

Scavando un po 'di più, si può vedere che il problema deriva da una differenza nel comportamento di collect:

In 2.9.2:

scala> Set(1).collect { case w => w } 
res1: scala.collection.immutable.Set[Int] = Set(1) 

In 2.10.0:

scala> Set(1).collect { case w => w } 
res4: scala.collection.immutable.Set[_ <: Int] = Set(1) 

Presumibilmente la ragione ha a che fare con il fatto che lo Set, a differenza, ad esempio List, è di tipo invariante. Ma una spiegazione più completa, e soprattutto quella che dà la motivazione per questo cambiamento, sarebbe grandiosa.

+0

Potrebbe essere quello di rendere le collezioni compatibile per la nuova dinamica Valori di valorizzazione - vale a dire le cose che "estendere" Int sarà ora accettata (supponendo che ho correttamente interpretato correttamente la nuova nozione di valori dinamici. – chaotic3quilibrium

risposta

6

È un bug. È anche possibile lavorare intorno ad esso digitando il modello, come in

scala> Set(1).collect { case w => w } 
res0: scala.collection.immutable.Set[_ <: Int] = Set(1) 

scala> Set(1).collect { case w: Int => w } 
res1: scala.collection.immutable.Set[Int] = Set(1)