2024 年 Clojure 状态调查! 中分享你的想法。

欢迎!请查阅 关于 页面以获取更多关于该功能的信息。

+3 投票
ClojureScript

如果你扩展一个类型以实现一个协议,随后创建该类型的实例,该实例在其元数据中包含相同的协议的实现,ClojureScript 仍将使用类型中的实现,而 Clojure 将使用更具体的元数据实现。

以下是基于 ClojureScript 协议元数据实现的一个测试的简要示例。

编辑:我无法将代码示例呈现在这个编辑器中,请参阅此 gist: https://gist.github.com/cjohansen/a24257ecb5db15c7e20aaa25ff713b30

(defprotocol ExtMetaProtocol
:extend-via-metadata true
(ext-meta-protocol [x]))

(ext-meta-protocol (with-meta {} {`ext-meta-protocol (fn [_] 1)})) ;;=> 1

(extend-type clojure.lang.PersistentArrayMap
ExtMetaProtocol
(ext-meta-protocol [m]

2))

(ext-meta-protocol {}) ;;=> 2
(ext-meta-protocol (with-meta {} {`ext-meta-protocol (fn [_] 1)})) ;;=> cljs => 2, clj => 1

1 答案

+3 投票

已确认 Clojure 1.10.1 和 ClojureScript 1.10.520 的行为有所不同,正如示例 REPL 会话中所述。对于 cljs,你必须将 extend-type clojure.lang.PersistentArrayMap 替换为 extend-type cljs.core.PersistentArrayMap

我建议您去Clojurians Slack的#cljs-dev频道,将ClojureScript开发者指向这个问题,查看他们是否已经知道它。

我实现了最初的:extend-via-metadata支持,并可以确认我是基于错误的假设实现的(即实际实现是在元信息之前被选择的)。

测试甚至反映了这个假设。
https://github.com/clojure/clojurescript/blob/d64b2333f3127b51dbe410874a7cdff4bac1edf8/src/test/cljs/cljs/core_test.cljs#L1756-L1777
您知道这被认为是JavaScript实现中的bug,值得更改吗?
是的,它可能应该与Clojure的行为相匹配。

然而,这意味着使用:extend-via-metadata的协议“总体上”会变“慢”,因为它不能采取目前所采用的“捷径”。
我刚刚遇到了这个问题。又是一个微妙的差异,这使得编写可移植代码成为一个问题。
...