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

欢迎!请参阅关于页面,了解如何运作的更多信息。

0
Spec
这个问题是在以下讨论语境中发现的 https://groups.google.com/d/msg/clojure/mIlKaOiujlo/tF71zZ2BCwAJ

规格错误报告失败的简单示例如下

他使用了一个无效的ns形式

(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

规格报告的错误

In: [1] val: ((require [clojure.spec :as s])) 失败在: [:args] 断言: (cat :docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs/ns-clauses),  额外输入
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


虽然错误在技术上是真的,但它没有显示报告的每个替代方案的s/cat失败的方式。

为了更好地理解为什么用户数据不正确,他应该确切知道规格尝试了什么以及它是如何失败的。

一个很好的例子是s/alt,其中所有失败的替代方案总是报告给用户。

这个问题已经被调查,首先是通过实验,然后是规格代码。  最后,一个补丁用于带来类似于s/alts的错误报告。

观察到规格针对具有可选分支的cat的错误报告行为如下

1. 如果cat在经过一个或多个可选分支后失败,则会报告整个cat失败
2. 如果cat在经过一个或多个可选分支并且随后有一个必需分支后失败,则只报告后面的必需分支,并且没有提及替代的可选分支。

规则1解释了ns示例。
规则2可能严重违反用户的直觉


(s/explain (s/cat :maybe-num (s/? number?)
                  :keyword keyword?)
           ["3"])


给出


In: [0] val: "3" 失败在: [:keyword] 断言: keyword?


报告清楚地没有解决用户想要输入数字的意图。  相反,他被告知应该输入一个关键字。

解决方案

已经编写了一个简单的补丁,将op-explain更改为以下行为

- 在s/cat中报告所有尝试过的替代方案。

它显著改进了报告的错误,因为它清楚地显示了用户数据是如何验证失败的。


(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

现在给出


ExceptionInfo 对clojure.core/ns的调用未符合规格
In: [1] val: (require [clojure.spec :as s]) 失败在: [:args :docstring] 断言: string?
In: [1] val: (require [clojure.spec :as s]) 失败在: [:args :attr-map] 断言: map?
In: [1 0] val: require 失败规格: :clojure.core.specs/ns-refer-clojure 在: [:args :clauses :refer-clojure :clause] 断言: #{:refer-clojure}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-require 在:[:args :clauses :require :clause] 断言:#{:require}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-import 在:[:args :clauses :import :clause] 断言:#{:import}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-use 在:[:args :clauses :use :clause] 断言:#{:use}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-refer 在:[:args :clauses :refer :clause] 断言:#{:refer}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-load 在:[:args :clauses :load :clause] 断言:#{:load}
输入:[1 0] val: require 失败规范::clojure.core.specs/ns-gen-class 在:[:args :clauses :gen-class :clause] 断言:#{:gen-class}
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


如果exlpain-data能够按:path的长度对::s/problems进行排序,那么将会把最初两个不必要的选项移动到后面。


(s/explain (s/cat :maybe-num (s/? number?)
                  :keyword keyword?)
           ["3"])


现在给出


输入:[0] val: "3" 失败在:[:maybe-num] 断言:number?
In: [0] val: "3" 失败在: [:keyword] 断言: keyword?


尽管可以构造出这种报告会产生更多噪音的例子(例如defn),但我相信这在上文所述原因是合理的

- 我们程序员总是在出错时向我们的用户请求最具体的信息 - 将此应用于规范错误报告是正确的
- 自定义错误报告器(s/*explain-out*)获取更多数据,以更好地匹配用户意图的窄报告

7 答案

0
通过
由:visibletrap_ 评论

我要在这里提出一个略微不同的问题,因为它有着相同的原因。

应该具体说明:fspec的:ret缺失,但它说在:args处失败。


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

(defn x [f] (f 1))

(s/fdef x
  :args (s/cat :f (s/fspec :args (s/cat :i int?))))

(st/instrument `x)

(x (fn [a] a))



主线程"main"中发生异常 clojure.lang.ExceptionInfo: 调用#user/x未符合规范
输入:[0] val: (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"])失败在:[:args] 断言:(cat :f (fspec :args (cat :i int?))),  额外输入
:clojure.spec/args  (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"])
:clojure.spec/failure  :instrument
:clojure.spec.test/caller  {:file "debug.clj", :line 16, :var-scope user/eval20}
 {:clojure.spec/problems [{:path [:args], :reason "Extra input", :pred (cat :f (fspec :args (cat :i int?))), :val (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :via [], :in [0]}], :clojure.spec/args (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :clojure.spec/failure  :instrument}
...
0
通过

由:lgs32a 评论

@alexmiller: 在发布1.9版本之前,我们是否可以决定这一点,因为这将从很大程度上改进错误信息。自最初在小组中的讨论以来,有关此类错误信息会修复的非直观错误信息报告更多。与此相关的是,按路径长度排序说明,如上所示(为其尚未创建问题跟踪)。
请征求Rich的意见。

0
通过

评论者:gshayban

与规范的工作正在进行中,并将发生在不受Clojure 1.9发布影响的单独git仓库中。我们将能够独立于Clojure更新规范依赖项并接收最终修复。

0
通过

由:lgs32a 评论

这影响了Clojure的编译时错误消息,而不仅仅是 opting 的 spec 部分。这部分编译器错误报告是有问题的,不应该随着主要版本一起发货。在这方面,spec 是否是独立的依赖项实际上并不重要。

此外,等待spec稳定版本来使用户不会必然更新他们的spec依赖项。

0
通过

由:lgs32a 评论

据我所知,更好的错误报告是 Spec 作为1.9依赖的唯一原因 - 请重新考虑。

0
通过

评论者:alexmiller

我不知道这将在1.9之前还是之后被考虑。根据我所阅读的,这似乎是合理的。

按路径长度排序的条目在 CLJ-2063 问题上,该问题于5月应用并随 spec.alpha 0.1.109发布。

0
通过
参考: https://clojure.atlassian.net/browse/CLJ-2013 (由lgs32a报告)
...