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 值,这在默认链接情况下有效,var 解引用转换为 ifn,调用,但在其他情况下(原生函数,直接链接,其他?)将不起作用

方法:考虑原生接口并使其工作,或者记录/失败说明仪表化在这种情况下不会工作。

11 答案

0 投票

评论者:hiredman

spec 用仪器的函数替换 var 值,这在默认链接情况下有效,var 解引用转换为 ifn,调用,但在其他情况下(原始函数、直接链接等)将不起作用

0 投票

评论者:kennyjwilli

嗯。至少应该记录下来。那么,spec 是否可以在带有类型提示参数的函数中使用?

0 投票

评论者:seancorfield

Spec 不能用于具有 原始 类型提示的参数或返回的函数 - 非原始类型提示似乎是可以的。

但是在这里,文档是不够的:对一个命名空间进行监视并从而发现它破坏了一个函数(这个函数刚好有一个原始类型提示)是不可以接受的。如果监视不起作用,函数应该跳过(并产生警告,希望如此)。

0 投票

评论者:hiredman

是的,我正在给出问题根本原因,而不是为问题找借口。

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

这样一个地方是直接链接的函数,但我觉得对于直接链接的函数来说,Clojure/Core会建议你只为测试而监视代码,并且你应只为生产而启用直接链接。

另一个我有些惊讶还没有更多关于它的讨论的例子是协议函数。

0 投票

评论者:seancorfield

您关于直接链接的评论让我对规约和监视 {{clojure.core}} 函数的有效性感到好奇。示例显示了 {{clojure.core/symbol}},但自1.8.0版起,Clojure的核心库就是直接链接的,对吧?

0 投票

评论者:hiredman

改变调用约定的是编译了直接链接的这个函数的调用者,而不是这个函数本身编译时启用了直接链接。

此代码将在直接链接关闭时抛出不符合的错误,并在直接链接开启时返回符号foo

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

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

(defn foo
[]
(symbol 'foo))

(s/instrument-all)

(foo)
`

0 投票

评论者: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

对Sean进行核心功能植入的测试将适用于从您的代码调用核心(这些调用可能是非直接链接的),但不会影响一个核心功能调用另一个核心功能,因为它们是直接链接的,并且不经过var。我们考虑很久的一件事是构建一个非直接链接的dev版本的核心,这样就可以在有潜在的开发时仪表示例或其他有用工具的场景下启动。

0 投票

评论者:seancorfield

感谢你的回答,@alexmiller -- 我们已经把dev设置为非直接链接,QA和产品设为直接链接,所以我只关心dev中{{(s/instrumental-all)}}可能出现的潜在问题,并想确保“代码不会中断”。如果仪器不会影响核心内现有的(直接链接的)调用,那就足够好了。我对原语提示和协议(以及任何可能冒出来的东西)感到担忧,因为你不希望被强迫阅读你包含的每个库的源代码,只是为了看看{{(s/instrument-all)}}是否安全,或它在开发过程中是否以某种奇怪的方式攻击你。

0 投票

由:borkdude发表的评论

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

鉴于这个错误似乎不会消失,也许Kondo应该注意到这一点吧?
0 投票
参考:https://clojure.atlassian.net/browse/CLJ-1941(由alex+import报告)
...