2010-04-08 5 views
16

Je sais que pour être Traversable, il vous suffit de disposer d'une méthode foreach. Iterable nécessite une méthode iterator.Dans les collections Scala 2.8, pourquoi le type Traversable a-t-il été ajouté au-dessus d'Iterable?

Le SID des collections Scala 2.8 et le papier «Combat Bitrot avec types» sont fondamentalement muets sur la question de savoir pourquoi Traversable a été ajouté. Le SID dit seulement "David McIver ... proposé Traversable comme une généralisation de Iterable".

Je vaguement rassemblé des discussions sur IRC qu'il doit faire avec des ressources lorsque la récupération traversal d'une collection se termine?

Ce qui suit est probablement liée à ma question. Il y a quelques définitions de fonctions impaires à la recherche dans TraversableLike.scala, par exemple:

def isEmpty: Boolean = { 
    var result = true 
    breakable { 
    for (x <- this) { 
     result = false 
     break 
    } 
    } 
    result 
} 

Je suppose qu'il ya une bonne raison qui n'a pas été simplement écrit:

def isEmpty: Boolean = { 
    for (x <- this) 
    return false 
    true 
} 
+0

'Traversable' est motivé dans Ch. 24 de la programmation à Scala, 2e éd .; dans certains cas, il est plus facile d'implémenter efficacement 'foreach' que 'itérateur'. – Blaisorblade

+0

En ce qui concerne la dernière question: https://github.com/scala/scala/pull/5101 – floating

Répondre

3

Je soupçonne que l'une des raisons est que c'est un beaucoup plus facile d'écrire une mise en œuvre concrète d'une collection avec une méthode abstraite foreach que pour un avec une méthode iterator abstraite. Par exemple, en C# vous pouvez écrire la mise en œuvre de la méthode GetEnumerator de IEnumerable<T> comme si elle était une méthode foreach:

IEnumerator<T> GetEnumerator() 
{ 
    yield return t1; 
    yield return t2; 
    yield return t3; 
} 

(. Le compilateur génère une machine d'état approprié pour conduire l'itération à travers le IEnumerator) En Scala, vous devrez écrire votre propre implémentation de Iterator[T] pour ce faire. Pour Traversable, vous pouvez faire l'équivalent de la mise en œuvre ci-dessus:

def foreach[U](f: A => U): Unit = { 
    f(t1); f(t2); f(t3) 
} 
+0

Je suis assez nouveau pour scala, mais puisque vous ne retournez rien, ne pourriez-vous pas écrire 'def foreach [U ] (f: A => U) {f (t1); f (t2); f (t3)} '? – tstenner

+0

'foreach' indique qu'il renvoie' Unit' et rejette donc le résultat du bloc de corps 'f (t3)' de type 'U'. –

9

J'ai demandé David McIver à ce sujet sur IRC. Il a dit qu'il ne se souvenait plus de toutes les raisons, mais ils inclus:

  • « itérateurs sont souvent ennuyeux ... à mettre en œuvre »

  • itérateurs sont « parfois dangereux (en raison de la configuration/désassemblage à le début et la fin de la boucle) »

  • -espériez pour des gains d'efficacité de la mise en œuvre des choses via foreach plutôt que par itérateurs (gains pas nécessairement encore fait preuve avec le compilateur HotSpot courant)

-3

juste au sujet de votre dernière question:

def isEmpty: Boolean = { 
    for (x <- this) 
    return false 
    true 
} 

Ce se traduit grossièrement par le compilateur à:

def isEmpty: Boolean = { 
    this.foreach(x => return false) 
    true 
} 

Vous êtes tout simplement pas en mesure de sortir de foreach, isEmpty retourne toujours vrai .

C'est la raison pour laquelle "hacky" Breakable a été construit qui sort de foreach en lançant une Control-Exception, l'attrapant en breakable et retourne.

+3

En fait, vous vous trompez sur le retour en Scala. Scala prend en charge les retours non-locaux. – Eastsun

+0

Eastsun a raison, car vous pouvez facilement vérifier dans le repl. –

+0

Euh, c'est étonnant, tu as raison. Est-ce que cela a toujours été valide ?? – hotzen

Questions connexes