分享您的想法,填写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,调用,但在其他情况(原始函数,直接链接,其他?)下则无法工作

方法: 考虑基本接口,并使其工作,或者记录/fail度量将无法与此类工作

11回答

0

评论由:hiredman 提出

spec 用已度量的函数替换 var 值,这对于默认链接情况有效,var 值解引用转换为 ifn,调用,但在其他情况(原始函数,直接链接,其他?)下则无法工作

0

评论由:kennyjwilli 提出

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

0

评论者:seancorfield

规范不能用于具有基本类型提示的参数或返回值的函数 -- 基本类型提示似乎可以。

但在这里的文档还不够:对一个命名空间进行代理然后发现它破坏了一个函数(恰好有一个基本类型提示)是不可接受的。如果代理无法工作,则应跳过该函数(并生成一个警告,希望如此)。

0

评论由:hiredman 提出

是的,我在说明问题的根本原因,而不是为问题开脱。

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

这样的一个地方是直接链接的函数,但我怀疑对于直接链接的函数,Clojure/Core可能只是建议你只为测试代码进行代理,并且你应在生产环境中仅开启直接链接。

另一个案例,让我有些惊讶的是,我们还没有听说更多有关内容是协议函数。

0

评论者:seancorfield

您关于直接链接的评论让我对为{{clojure.core}}函数规范和代理的有效性产生了疑问。示例显示了{{clojure.core/symbol}},但既然Clojure的核心库从1.8.0版本开始是直接链接的,这不应该是吗?

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。我们长期以来一直在考虑构建一个免税版的开发版核心,该版本不会直接链接,并可能启动原理分析或其他有助于开发时间的工具。

0

评论者:seancorfield

感谢您的回答 @alexmiller。我们已经将开发设置为非直接链接,而将QA /生产设置为直接链接,所以我只担心{{(s/instrumential-all)}}在开发中可能存在的问题,并希望确保“代码不会损坏”。如果原理分析不会影响现有(直接链接)的核心函数调用,那就足够好了。我担心原始提示、协议(以及所有可能出问题的东西),因为您不希望被迫阅读您包含的每个库的源代码,只是为了确定{{(s/instrument-all)}}是否安全或它会在您开发过程中以某种奇怪的方式伤害您。

0

评论者:borkdude

在规格说明 clojure.core/partition-all 时遇到了这个问题。

鉴于这个错误似乎会持续存在,也许我们应该让Kondo知道这个问题?
0
参考:[https://clojure.atlassian.net/browse/CLJ-1941](https://clojure.atlassian.net/browse/CLJ-1941)(由alex+import报告)
...