2010-09-09 13 views
20

Entonces, por ejemplo, ¿por qué se compila List(1,2,3,4).contains("wtf")? ¿No sería bueno si el compilador lo rechazara?Scala: ¿Por qué Seq.contains toma un argumento Any, en lugar de un argumento del tipo de secuencia?

+0

¿La lista es genérica en Scala, por lo que solo acepta elementos de un tipo? –

+0

Probablemente Scala lo hace de esta manera porque así es como lo hace Java ('Collection .contains' también toma un argumento de tipo' Object', no 'T'), aunque admitidamente eso no es una gran respuesta. – sepp2k

Respuesta

18

Muchas respuestas interesantes, pero esta es mi propia teoría: si contains no recibió un , entonces Seq no podría ser covariante.

Véase, por ejemplo, Set, que no es co-variante y cuya contains toma un A en lugar de un Any.

Las razones de esto se dejan como un ejercicio para el lector. ;-) Pero aquí hay una pista:

scala> class Container[+A](elements: A*) {       
    | def contains(what: A): Boolean = elements exists (what ==) 
    | } 
<console>:7: error: covariant type A occurs in contravariant position in type A of value what 
     def contains(what: A): Boolean = elements exists (what ==) 
        ^
+0

Ah. Otros han hecho puntos interesantes (¡gracias a todos!), Pero apuesto a que esta es la verdadera razón. –

+5

Y para responder el "ejercicio para el lector" de Daniel: si Seq es covariante, entonces p. un Seq [Int] debe calificar como Seq [Cualquiera], entonces debo poder pasar cualquier cosa a su método contains. –

+0

Ah, y luego quería saber por qué Set es invariante. Eso se responde aquí: http://stackoverflow.com/questions/676615/why-is-scalas-immutable-set-not-covariant-in-its-type –

1

SeqLike.contains comprueba si hay un valor presente al buscar un elemento en la secuencia que sea igual al valor (utilizando ==). == toma una Any, así que sospecho que esta es la razón.

+0

Sí, la relación de equivalencia no requiere que dos objetos tengan el mismo tipo. Es discutible que el método 'contains' se adapte al caso común (donde objetos iguales tienen el mismo tipo) ya que el método' exists' podría usarse para implementar una prueba más general. –

+0

Eso no es realmente una razón, ¿verdad? Ha habido una decisión consciente de usar == en lugar de lo que sea el equivalente de Scala de .equals(). Entonces, la verdadera respuesta reside en la decisión más que en la implementación. – dty

+0

@Danny En realidad, '==' * es * el equivalente de Scala de Java 'equals()'. Como Dave Griffith explicó, tanto Java como Scala usan igualdad sin tipo. –

4

"contiene" es fundamentalmente sobre pruebas de igualdad, y la igualdad en Scala (como en Java antes) está sin tipo. El valor práctico de tener igualdad sin tipo es pequeño, pero no cero. Hay, por ejemplo, algunas ocasiones en las que tiene sentido que dos objetos de diferentes clases sean iguales entre sí. Por ejemplo, puede desear que un objeto de tipo RGBColor sea igual a un PantoneColor si definen el mismo matiz, o un HashSet inmutable y un TreeSet inmutables iguales si contienen los mismos elementos. Dicho esto, la igualdad no tipificada también causa muchos dolores de cabeza, y el hecho de que el compilador pueda detectar fácilmente que List(1,2,3,4).contains("wtf") es absurdo, pero no lo es.

La mayoría de las herramientas de búsqueda de errores de Java incluyen pruebas para detectar la presencia de improbables usos de igualdad no tipificada. (Escribí las inspecciones para hacer esto en IntelliJ IDEA.) No me cabe duda de que cuando las herramientas de detección de fallas de Scala se conecten, estos se encontrarán entre los primeros errores detectados.

+2

Ah, debería mencionar que si quieres jugar con la igualdad de tipeo en lugar de igualdad sin tipo, echa un vistazo a la construcción Equals en la biblioteca de scalaz. En un mundo perfecto, las colecciones serían parametrizables sobre su predicado de prueba de igualdad, pero en el mundo real las bibliotecas todavía no están allí. –

+1

Un caso de uso que encontré: 'List (1,2,3,4) .contains (BigInt (" 2 "))' da como resultado 'true'. Personalmente, creo que se podría haber logrado con clases de implicits/type en lugar de hacer 'contains' /' exists' tomar 'Any' ... – soc

Cuestiones relacionadas