Scala: Почему Seq.contains принимает аргумент Any, а не аргумент типа последовательности?

Так, например, почему List(1,2,3,4).contains("wtf") даже компилируется? Было бы неплохо, если бы компилятор это отклонил?


person Seth Tisue    schedule 09.09.2010    source источник
comment
Является ли List универсальным в Scala, поэтому он принимает элементы только одного типа?   -  person Lasse V. Karlsen    schedule 09.09.2010
comment
Предположительно, scala делает это таким образом, потому что именно так это делает java (Collection<T>.contains также принимает аргумент типа Object, а не T), хотя, по общему признанию, это не так много ответа.   -  person sepp2k    schedule 09.09.2010


Ответы (3)


Множество интересных ответов, но вот моя собственная теория: если contains не получил Any, то Seq не может быть совместным вариантом.

См., Например, Set, который не совпадает с вариантом и contains принимает A вместо Any.

Причины этого оставим читателю в качестве упражнения. ;-) Но вот подсказка:

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 ==)
                      ^
person Daniel C. Sobral    schedule 09.09.2010
comment
Ах. Другие высказали интересные замечания (всем спасибо!), Но я уверен, что это настоящая причина. - person Seth Tisue; 09.09.2010
comment
И чтобы ответить на упражнение Даниила для читателя: если Seq ковариантен, то, например, Seq [Int] должен квалифицироваться как Seq [Any], поэтому я должен иметь возможность передавать что-либо в его содержащий метод. - person Seth Tisue; 09.09.2010
comment
О, а потом я хотел узнать, почему Set инвариантен. Здесь ответили: stackoverflow.com/questions/676615/ - person Seth Tisue; 09.09.2010
comment
Просто используйте -Xfatal-warnings, чтобы компиляция не прошла - person Joan; 09.07.2019

"contains" в основном относится к проверке равенства, а равенство в Scala (как и в Java до него) нетипизировано. Практическая ценность нетипизированного равенства мала, но не равна нулю. Есть, например, несколько случаев, когда имеет смысл, чтобы два объекта разных классов были равны друг другу. Например, вы можете пожелать, чтобы объект типа RGBColor был равен PantoneColor, если они определяют один и тот же оттенок, или неизменяемый HashSet и неизменный TreeSet были равны, если они содержат одинаковые элементы. Тем не менее, нетипизированное равенство также вызывает кучу головных болей, и тот факт, что компилятор мог легко уловить это List(1,2,3,4).contains("wtf"), бессмысленно, но не будет, является одним из них.

Большинство инструментов для поиска ошибок Java включают тесты для обнаружения невероятных вариантов использования нетипизированного равенства. (Я написал инспекции, чтобы сделать это в IntelliJ IDEA.) Я не сомневаюсь, что когда появятся инструменты поиска ошибок Scala, они будут среди первых обнаруженных ошибок.

person Dave Griffith    schedule 09.09.2010
comment
О, я должен упомянуть, что если вы хотите поиграть с типизированным равенством вместо нетипизированного равенства, проверьте конструкцию Equals в библиотеке scalaz. В идеальном мире коллекции можно было бы параметризовать с помощью предиката проверки равенства, но в реальном мире библиотек еще нет. - person Dave Griffith; 09.09.2010
comment
Я нашел один вариант использования: List(1,2,3,4).contains(BigInt("2")) приводит к true. Лично я думаю, что этого можно было достичь с помощью классов неявных / типов вместо того, чтобы заставлять _3 _ / _ 4_ принимать Any ... - person soc; 10.09.2010

SeqLike.contains проверяет, присутствует ли значение, проверяя элемент в последовательности, который равен значению (с помощью ==). == принимает Any, поэтому я подозреваю, что это причина.

person denis phillips    schedule 09.09.2010
comment
Да, отношение эквивалентности не требует, чтобы два объекта имели один и тот же тип. Можно утверждать, что метод contains должен соответствовать общему случаю (когда одинаковые объекты имеют один и тот же тип), поскольку метод exists может использоваться для реализации более общего теста. - person Aaron Novstrup; 09.09.2010
comment
На самом деле это не причина, не так ли. Было принято осознанное решение использовать == вместо того, что является эквивалентом .equals () в Scala. Итак, настоящий ответ заключается в решении, а не в реализации. - person dty; 09.09.2010
comment
@Danny На самом деле == является эквивалентом Java equals() в Scala. Как объяснил Дэйв Гриффит, и Java, и Scala используют нетипизированное равенство. - person Aaron Novstrup; 09.09.2010
comment
@Danny: Я согласен с этим до некоторой степени. В какой-то момент дизайна вы должны спросить, что значит содержать элемент, и указать, что они равны по отношению к ==, имеет смысл. Конечно, вы можете ограничить то, что содержит accept, и по-прежнему использовать ==, так что именно здесь решение вступает в игру (как вы указываете). То, что == принимает Any, вероятно, повлияло на решение. - person denis phillips; 09.09.2010