2010-05-16 17 views
3

Pourquoi l'appel à fn (Iterator ("foo") compile, mais l'appel à fn (fooIterator) échoue avec une erreur "incompatibilité de type; found: Iterator [java.lang.String] requis: scala.Iterator [ com.banshee.Qx.HasLength] "Quelle est la différence entre ces deux appels à une fonction prenant une collection de types structurels?

object Qx { 
    type HasLength = {def length: Int} 
    def fn(xs: Iterator[HasLength]) = 3 
    var tn = fn(Iterator("foo")) 
    var fooIterator = Iterator("foo") 
    var tnFails = fn(fooIterator) //doesn't compile 
} 

sont-ils pas la même chose

+0

Pouvez-vous poster des singnatures de type des itérateurs? Peut-il y avoir des annotations ou des implicits de variance? – Dario

+0

Ceci est juste la bibliothèque standard, aucun code supplémentaire nécessaire. scala> iterator ("foo") res0: iterator [java.lang.String] = non vide iterator –

Répondre

3

Il doit être un bogue dans la représentation des raffinements, car les deux formules suivantes les deux fonctionnent.

object Qx1 { 
    // give length() parens, even though the Iterator definition doesn't have them 
    type HasLength = { def length(): Int } 

    def fn(xs: Iterator[HasLength]) = 3 
    var tn = fn(Iterator("foo")) 
    var fooIterator = Iterator("foo") 
    var tnFails = fn(fooIterator) //doesn't compile 
} 

object Qx2 { 
    type HasLength = { def length: Int } 

    def fn(xs: Iterator[HasLength]) = 3 
    var tn = fn(Iterator("foo")) 
    // annotate the type of fooIterator before the type inferencer can mis-infer 
    var fooIterator: Iterator[HasLength] = Iterator("foo") 
    var tnFails = fn(fooIterator) //doesn't compile 
} 

Edit:

trop tôt le matin. C'est String avec la méthode length(), qui a des parens, ce qui signifie que c'est juste et que vous avez tort de penser que length et length() sont la même méthode. (C'est un joli petit piège que j'ai documenté auparavant.)

+0

Si c'est juste longueur v. Length(), son premier exemple ne devrait-il pas échouer aussi? var tn = fn (Iterator ("foo")) –

+0

Et pourquoi la version de Randall Schulz fonctionne-t-elle avec la projection de vue? Je suis un peu déconcerté. –

+1

C'est juste la longueur par rapport à la longueur. fn (Iterator ("foo")) fonctionne pour la même raison en annotant le type de fooIterator: le type attendu de l'expression influence le type déduit. Dans l'exemple défaillant, un type incompatible est déduit dans la déclaration, puis l'appel est fait dans une instruction séparée. – extempore

3

Cette formulation fonctionne:

object Qx { 
    type HasLength = {def length: Int} 
    def fn[HL <% HasLength](xs: Iterator[HL]) = 3 
    val tn = fn(Iterator("foo")) 
    val fooIterator = Iterator("foo") 
    val tnFails = fn(fooIterator) 
} 
+0

J'aimerais une explication unifiée de ce commentaire et le commentaire de improvisa à propos de zéro argument longueur VS- longueur-avec-vide-parens. J'ai le sentiment qu'il se passe quelque chose de subtil ici que je ne comprends pas. –