2009-03-24 7 views
83

EDIT: Réécrit cette question sur la base réponse originalePourquoi l'ensemble immuable de Scala n'est-il pas covariant dans son type?

La classe scala.collection.immutable.Set est covariante pas dans son paramètre de type. Pourquoi est-ce?

import scala.collection.immutable._ 

def foo(s: Set[CharSequence]): Unit = { 
    println(s) 
} 

def bar(): Unit = { 
    val s: Set[String] = Set("Hello", "World"); 
    foo(s); //DOES NOT COMPILE, regardless of whether type is declared 
      //explicitly in the val s declaration 
} 
+0

Il convient de noter que 'foo (s.toSet [CharSequence])' compile bien. La méthode 'toSet' est O (1) - elle ne fait qu'intégrer' asInstanceOf'. –

+1

Notez également que 'foo (Set (" Hello "," World "))' se compile aussi sur 2.10, puisque Scala semble être en mesure d'inférer le bon type de Set. Il ne fonctionne pas avec les conversions implicites (http://stackoverflow.com/questions/23274033/implicit-definition-working-for-seq-but-not-for-set/). –

Répondre

48

Set est invariant dans son paramètre de type en raison du concept derrière les ensembles en tant que fonctions. Les signatures suivantes devraient clarifier les choses légèrement:

trait Set[A] extends (A=>Boolean) { 
    def apply(e: A): Boolean 
} 

Si Set ont été Covariant dans A, la méthode apply serait incapable de prendre un paramètre de type A en raison de la contravariance des fonctions. Set pourraient être contravariante dans A, mais cela provoque aussi des problèmes lorsque vous voulez faire des choses comme ceci:

def elements: Iterable[A] 

En bref, la meilleure solution est de garder invariante choses, même pour la structure de données immuables. Vous remarquerez que immutable.Map est également invariant dans l'un de ses paramètres de type.

+4

Je suppose que cet argument s'articule autour de "le concept derrière les ensembles en tant que fonctions" - pourrait-il être développé? Par exemple, quels avantages "un ensemble en tant que fonction" donnez-moi qu'un "ensemble comme une collection" ne vaut pas la peine de perdre l'utilisation de ce type covariant? –

+0

À la lumière de votre réponse, voulez-vous (en général) * pas * utiliser Set comme le type retourné par une API?Je voudrais généralement avoir une implémentation de service garder un ensemble interne en Java, avec l'API de service elle-même envelopper dans une collection. non modifiable sur une méthode d'accès. –

+0

Je pense que je vais poser une question connexe –

5

EDIT: pour ceux qui se demandent pourquoi cette réponse semble un peu hors-sujet, cela est parce que je (le questionneur) ont modifié la question.

L'inférence de type Scala est assez bonne pour comprendre que vous voulez des CharSequences et non des Strings dans certaines situations. En particulier, les travaux suivants pour moi dans 2.7.3:

import scala.collections.immutable._ 
def findCharSequences(): Set[CharSequence] = Set("Hello", "World") 

Quant à la façon de créer immutable.HashSets directement: non. En tant qu'optimisation d'implémentation, les HashSets immuables de moins de 5 éléments ne sont pas réellement des instances d'immutable.HashSet. Ils sont soit EmptySet, Set1, Set2, Set3 ou Set4. Ces classes sous-classe immutable.Set, mais pas immutable.HashSet.

+0

Vous avez raison; en essayant de simplifier mon exemple réel, j'ai fait une erreur triviale :-( –

46

à http://www.scala-lang.org/node/9764 Martin Odersky écrit:

« Sur la question des ensembles, je crois que les tiges non-variance également des implémentations ensembles communs sont mis en œuvre comme hashtables, qui sont des tableaux non variante du. Je suis d'accord que c'est une irrégularité un peu ennuyante. "

Ainsi, il semble que tous nos efforts pour construire une raison de principe pour cela était peu judicieux :-)

+1

Mais certaines séquences sont aussi implémentées avec des tableaux, et toujours 'Seq' est covariant ... suis-je en train de manquer quelque chose? –

+2

Cela peut être trivialement résolu en stockant 'Array [Any]' en interne. – rightfold

+0

@rightfold est correct. Il pourrait y avoir une raison raisonnable, mais ce n'est pas ça. –

Questions connexes