2024 Clojure现状调查中分享您的想法!

欢迎!请参见关于页面以获取更多关于这是如何工作的信息。

+1表决
Spec

`
(require '[clojure.spec :as s] '[clojure.spec.test :as st])
(defn foo [^double val] val)
(s/fdef foo :args (s/cat :val double?))
(st/instrument `foo)
(foo 5.2)

user=> (foo 5.2)
ClassCastException clojure.spec.test$spec_checking_fn$fn__13069不能被转换到clojure.lang.IFn$DO

   	user/eval6 (NO_SOURCE_FILE:5)
   	user/eval6 (NO_SOURCE_FILE:5)
   	clojure.lang.Compiler.eval (Compiler.java:6951)
   	clojure.lang.Compiler.eval (Compiler.java:6914)
   	clojure.core/eval (core.clj:3187)
   	clojure.core/eval (core.clj:3183)
   	clojure.main/repl/read-eval-print--9704/fn--9707 (main.clj:241)
   	clojure.main/repl/read-eval-print--9704 (main.clj:241)
   	clojure.main/repl/fn--9713 (main.clj:259)
   	clojure.main/repl (main.clj:259)
   	clojure.main/repl-opt (main.clj:323)
   	clojure.main/main (main.clj:422)

`

原因: spec通过使用不会与原始函数接口一起工作的仪表化函数替换var值

方法: 考虑原始接口,使它们正常工作,或在文档中记录/失败这些工具不会与此一起工作。

11 答案

0表决

评论:hiredman

spec通过将var值替换为仪表化函数,这使得默认链接情况有效,将var解引用转换为ifn,调用,但在其他情况(原始函数,直接链接,其他?)中不会工作。

0表决

评论:kennyjwilli

嗯。至少应该有文档说明。所以,spec不能用于具有类型提示参数的函数?

0表决

评论作者:seancorfield

规范不能用于带有原始类型提示参数或返回值的函数 -- 非原始类型提示似乎没问题。

但这里的文档还不够:监控一个命名空间然后发现它破坏了一个函数(碰巧有原始类型提示)是不可接受的。如果监控不起作用,应该跳过这个函数(并产生警告,最好是如此)。

0表决
by

评论:hiredman

是的,我正在提供问题的根本原因,而不是为问题开脱。

理解根本原因可以预测其他可能出现问题的位置:任何使用非默认函数链接策略的地方。

其中一个地方是直接链接的函数,但我怀疑对于直接链接的函数,Clojure/Core 告诉你只应该为测试代码进行监控,并且你应该只在生产中打开直接链接。

另一个案例,我觉得我们还没有听到更多的关于这个案例,那就是协议函数。

0表决
by

评论作者:seancorfield

你对直接链接的评论让我思考为{{clojure.core}}函数规范化和监控的有效性。示例显示{{clojure.core/symbol}},但 Clojure 的核心库是从 1.8.0 版本开始作为直接链接的,不是吗?

0表决
by

评论:hiredman

改变调用约定不是函数通过直接链接编译,而是该函数的调用者通过直接链接编译。

此代码将在直接链接关闭的情况下产生不符合规范的错误,并在直接链接打开的情况下返回符号 foo

`
(require '[clojure.spec :as s])

(s/fdef symbol
:args string?
:ret symbol?)

(defn foo
[]
(symbol 'foo))

(s/instrument-all)

(foo)
`

0表决
by

评论:hiredman

此代码返回 true 因为 m 是协议函数,如果你将其替换为常规函数,它将抛出不符合规范的错误

`
(require '[clojure.spec :as s])

(defprotocol P
(m [_]))

(deftype T []
P
(m [_] true))

(s/fdef m
:args (s/cat :p (constantly false))
:ret string?)

(defn foo
[]
(m (T.)))

(s/instrument-all)

(foo)
`

0表决

评论者:alexmiller

使用原生类型提示进行核心函数的indexing将适用于从您的代码到内核的调用(这些调用可能没有直接链接),但是不会影响一个核心函数到另一个核心函数的调用,因为这些调用是直接链接的,不需要通过变量。我们长期以来一直在考虑构建一个不直接链接的开发版内核,这样就可以开启indexing或其他有助于开发时间工具的支持。

0表决

评论作者:seancorfield

感谢您的回答 @alexmiller – 我们已将开发设置为非直接链接,但QA/生产设置为直接链接,所以我只担心开发中可能出现的问题,希望确保“代码不会破坏”。如果indexing不会影响内核中的现有(直接链接)调用,那么对我来说就足够好了。我担心原生类型提示和协议(以及任何爬出来的东西),因为您不需要阅读您包含的每一个库的源代码,只是想看看{{(s/instrument-all)}}是否安全,或者您在开发过程中是否会有一些奇怪的方式被“咬住”。

0表决

评论者:borkdude

在spec clojure.core/partition-all时遇到此问题。

由于此错误似乎将长期存在,也许这是Kondo应该知道的事情吗?
0表决
参考: https://clojure.atlassian.net/browse/CLJ-1941 (由 alex+import 报告)
...