clojure extend-type vs deftype和protocol implementation

时间:2017-04-21 15:11:43

标签: types clojure extend

e-book about specter中,有这段话:

  

我们需要像这样定义ALL的类型:

     

(deftype AllType [])

     

最后,我们需要添加AllType   select *

的实现
(extend-type AllType   Navigator   (select*
[this structure continuation]
    ...))
     

(如果您熟悉协议,您可能想知道为什么我们在定义类型时不定义select *:

(deftype AllType []
  Navigator
  (select* [this structure continuation]
    ...))
     

原因是特定协议功能的依赖于实现的查找对于以这种方式定义的函数不起作用。)

我真的没有得到作者在这里想说的话。 extend-typedeftype +就地实施之间有什么区别?

1 个答案:

答案 0 :(得分:2)

我刚读完the Clojure Polymorphism book,在上一章中对此进行了讨论。您可能希望查看更多详细信息。

它的要点是它们在概念上看起来是一样的,但它们不是。 他描述了一个语义“gotcha”,因为Java类也定义了一个名称空间。例如:

(ns my.ns)
(defprotocol Foo  (run [this]))

(ns your.ns)
(defprotocol Foo  (run [this]))

(ns user)
(defrecord FooAble [])
(extend-protocol my.ns/Foo
  FooAble
  (run [this] (println "Foo Me")))
(extend-protocol your.ns/Foo
  FooAble
  (run [this] (println "Foo You")))

(println 1 (->FooAble))
(def some-foo (->FooAble))

(my.ns/run   some-foo)  => Foo Me
(your.ns/run some-foo)  => Foo You

在Java中你会试着说

someFoo.run()  =>  Which `run` method...?

所以在Clojure中我可以使用2个run方法同名并且如果我使用extend-protocol,则在单个对象上签名。如果我尝试定义内联它崩溃:

(defrecord BeerAble []
  my.ns/Beer
  (run [this] (println "Beer Me"))
  your.ns/Beer
  (run [this] (println "Beer You")))

(println 2 (->BeerAble))
(def some-beer (->BeerAble))

(my.ns/run   some-beer)
(your.ns/run some-beer)

;=>  CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file user/BeerAble,

因此,内联定义就像尝试使用两种void run()方法来实现Java接口。为了使它工作,您必须将方法名称更改为myRunyourRun,如果两个外部库已经选择了函数名称run,那么它最好也是不可能的,现在是冲突。

如果没有阅读幽灵书,我不能说这是否直接回答了原始问题,但您可能希望尝试一下。除非你遇到冲突的命名空间/功能问题,否则你应该得到相同的结果。您还可以对程序进行概要分析,以确定是否有一个加速了您的程序。

现在更仔细地看一下文本,我看不出它引用的用例应该有什么不同。您可以尝试验证答案。