Clojure Protocols против Scala Структурные Типы
После просмотра интервью с Ричем Хикки о протоколах в Clojure 1.2 и очень мало зная о Clojure, у меня есть несколько вопросов о протоколах Clojure:
- Они предназначены для того же, что и структурные типы в Scala? Какие преимущества имеют протоколы по сравнению со структурными типами (производительность, гибкость, четкость кода и т. Д.)? Они реализованы через отражения?
- Вопросы по взаимодействию со Scala: можно ли использовать протоколы вместо структурных типов в Scala? Могут ли они быть расширены (если термин "продление" может применяться к протоколам) в Scala?
4 ответа
Совершенно не связаны.
Скала - статически типизированный язык. Clojure - это динамически типизированный язык. Это различие формирует их обоих в корне.
Структурные типы - это статические типы, точка. Это просто способ заставить статически доказать компилятору, что объект будет иметь определенную структуру (я говорю "докажи здесь", но приведение может вызвать ложные доказательства, как всегда).
Протоколы в Clojure - это способ создать динамическую диспетчеризацию, которая намного быстрее, чем отражение или поиск объектов на карте. В семантическом смысле они на самом деле не расширяют возможности Clojure, но в оперативном отношении они значительно быстрее, чем механизмы, используемые ранее.
Черты Scala немного ближе к протоколам, как и интерфейсы Java, но, опять же, есть проблема статики и динамики. Черты Scala должны быть связаны с классом во время компиляции, подобно интерфейсам Java. Протоколы Clojure могут быть добавлены к типу данных во время выполнения даже после того, как это произошло даже третьей стороной.
Нечто подобное протоколам Clojure возможно в Java и Scala с помощью таких механизмов, как шаблоны оболочки / прокси или динамические прокси ( http://download.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html). Но они будут чертовски неуклюжими по сравнению с протоколами Clojure, и получить правильную идентификацию объекта также сложно.
Цель Protocols in Clojure - эффективно решить проблему выражения.
[См.: Простое объяснение протоколов clojure. ]
Решение проблемы выражения в Scala - это последствия. Итак, семантически это самый близкий эквивалент Clojure Protocols в Scala. (В Haskell это будут классы типов или семейства типов.)
Как я понял из этого вступительного поста в блоге, протоколы закрытия ближе к чертам Scala, а не к структурным типам (и, следовательно, не могут использоваться в качестве замены для них, отвечая на мой второй вопрос):
/* ----------------------- */
/* --- Protocol definition */
/* ----------------------- */
(defprotocol Fly
"A simple protocol for flying"
(fly [this] "Method to fly"))
/* --- In Scala */
trait Fly{
def fly: String
}
/* --------------------------- */
/* --- Protocol implementation */
/* --------------------------- */
(defrecord Bird [nom species]
Fly
(fly [this] (str (:nom this) " flies..."))
/* --- In Scala */
case class Bird(nom: String, species: String) extends Fly{
def fly = "%s flies..." format(nom)
}
/* --------------------- */
/* --- Dynamic extension */
/* --------------------- */
(defprotocol Walk
"A simple protocol to make birds walk"
(walk [this] "Birds want to walk too!"))
(extend-type Bird
Walk
(walk [this] (str (:nom this) " walks too..."))
/* --- In Scala */
trait Walk{
def walk = "Birds want to walk too!"
}
implicit def WalkingBird(bird: Bird) = new Walk{
override def walk = "%s walks too..." format(bird.nom)
}
/* --------------- */
/* --- Reification */
/* --------------- */
(def pig (reify
Fly (fly [_] "Swine flu...")
Walk (walk [_] "Pig-man walking...")))
/* --- In Scala */
object pig extends Fly with Walk{
def fly = "Swine flu..."
override def walk = "Pig-man walking..."
}
Другие ответы лучше подходят к другим частям вашего вопроса, но:
Они реализованы через отражения?
Нет - протоколы компилируются в интерфейсы JVM. Вещи, которые реализуют протоколы (reify, defrecord и т. Д.), Компилируются в классы JVM, которые реализуют интерфейс протокола, поэтому вызовы функций протокола аналогичны вызовам стандартных методов JVM.
Фактически это было одним из мотиваторов для протоколов - многие внутренние структуры данных Clojure были написаны на Java по соображениям скорости, потому что не было никакого способа сделать полиморфную диспетчеризацию с полной скоростью в чистом Clojure. Протоколы обеспечивают это. Clojure по-прежнему имеет много Java в своем исходном коде, но теперь все это можно переписать в Clojure без потери производительности.