请在2024 Clojure状态调查!中分享您的想法。

欢迎!请查看关于页面以了解更多有关如何使用本站的信息。

+3
错误

另一项Clojure状态调查以及“错误消息”仍然是改进的首要任务。

Slack上的讨论导致许多关于异常和错误消息的入门难题。我希望在此处关注的一个是为(pst)提供一个入门友好替代品。

目前,(pst)在尽可能清晰地显示堆栈跟踪方面做出了合理尝试,消除了“噪音”,并缩减了一些堆栈跟踪——但它对于入门者来说仍然不够理想,这些入门者在理解某些异常以及导航(Java风格)堆栈跟踪方面有困难,尤其是与其他一些努力提供用户友好错误消息和堆栈跟踪的语言相比。

Slack中的一个例子是

(defn f [i]
  (fn [j]
    (/ j i)))

(run! #(% 1) (map f (range 3)))

REPL中打印的异常没问题,但显示了

user=> (pst)
ArithmeticException Divide by zero
        clojure.lang.Numbers.divide (Numbers.java:190)
        user/f/fn--16571 (NO_SOURCE_FILE:3)
        user/eval16576/fn--16577 (NO_SOURCE_FILE:1)
        clojure.core/run!/fn--8906 (core.clj:7849)
...

省略的部分提到了clojure.lang.ArrayChunk.reduce,然后对clojure.core.protocols的内容有多次引用(并且默认没有足够深入地显示clojure.core/run!的原始调用)。

我认为这里有机会创建一个新的clojure.repl/explain函数,它接受与pst相同的参数,提供对失败情况的更详细说明,同时进一步减少pst目前显示的堆栈跟踪中的噪音。

理想的情况下,可以通过对核心进行一些基本清理来实现这一点,但有一些动态钩子,允许其他工具“安装”额外的扩展和/或清理,以便社区可以提供库和功能,进一步改善初学者的体验。

例如,一个动态钩子到ex-str,将允许社区提供的工具对显示的异常消息进行按摩(对于原始REPL输入以及对explain),以便将入门者难以理解的消息(如class <whatever>不能被转换为clojure.lang.IFn...)改写成入门友好语言的(如期望函数-找到 <whatever>)。

类似的功能会将堆栈帧过滤到字符串中,从而使输出对初学者更友好。

在处理宏或语法错误(打字错误)时,我经常遇到难以解密的错误。

就我个人而言,当我看到“无法转换”错误时,我希望能看到“无法转换”的实际值——而不是“类Symbol无法转换为ISeq”,而是更好的是看到“类Symbol (`实际符号`) 无法转换为ISeq”,这样更容易找到打字错误或问题所在。当然,许多不透明的类无法有意义地toString,但我认为有一些比没有好。我明白这些错误来自Java方面,因此添加额外信息可能不是微不足道的,但仍然很棒。

我还经常遇到神秘且难以阅读的规范错误,这些错误要么需要长时间用肉眼解析,要么我必须使用一些库来为我美化打印它们(为什么我需要库来使语言错误可读?)。最好能有关于“调用defn不符合规范”的便于理解的解释。可能除了(而不是代替)当前的输出。
by
当你遇到这种语法或规范案例时,请来这里提交一个问题!

ClassCast异常是由jvm生成的(在字面意义上的每个函数调用中),因此我们很难增强这个特定案例(除非我们围绕每个转换发出更多的代码)。但对于这些,如果你遇到一个令人困惑的错误,请在这里提交一个问题。
by
在REPL或测试中,对这些发出更多的代码将会非常棒,老实说。

如果Clojure默认到一个运行模式,可以在REPL或测试中清楚地显示错误,相对于其实现细节,我认为这对错误信息来说将会很棒。

1 答案

+4 推荐
by

这里至少有两种、可能更多的问题/想法,区分它们会很有帮助。前缀/钩子想法似乎是不相关的。

一个严肃的问题 - 如果错误消息是好的(你说在这里),工具从未显示堆栈跟踪,为什么这是初学者的问题?错误消息试图显示源错误的好位置(考虑到宏的程度)。

"友好的新用户"这个问题,我认为,不是一个正确的框架,因为它并没有说到问题的实质。如果堆栈跟踪可以更加阐明问题,那么它将同时对初学者和非初学者都有用,我们也可以具体地列出理解堆栈跟踪的挑战。我想先说出这些...

  1. Clojure函数调用通常在每次调用涉及到2个或3个帧
  2. 匿名函数有隐晦的名字
  3. 在某些情况下,匿名函数是由实现隐式创建的
  4. 用户调用宏,但堆栈跟踪处理的是展开的代码(你写的代码 != 你运行的代码) - 这对错误信息和堆栈跟踪都是根本问题
  5. 宏代码常常创建gensym名称,这些名称变成类名称
  6. REPL基础设施在堆栈中
  7. 工具基础设施在堆栈中(打印机、nrepl、中间件)
  8. Clojure核心库和Clojure Java实现混合
  9. 堆栈跟踪不仅会显示Clojure命名空间或Java类,而且还会冗余地显示文件名
  10. 行号与源代码不正确关联
  11. 惰性效应

一个"简化的堆栈跟踪"函数需要清楚哪些这些或其他潜在问题实际上是重要的。其中一些相当简单,而另一些则相当困难。

请注意,展示现实的一种不同视角总是与隐藏最初为什么查看堆栈跟踪所需要的信息的风险相矛盾。

如果简化的堆栈打印函数是有用的,那么这可以独立于核心完成。特别是,开发工具在这一点上处于一个很好的位置。

by
我要坦白,我只是传话者。

除了对于那些需要更好解释的ClassCastException经常出现的初学者之外,我认为信息是好的,我最初打算为ex-str钩子创建一个单独的“询问” - 所以,是的,我应该把它分开。

我不知道如何措辞这个问题 - 我也没有看到其他人很好地界定它。它只是一直是“错误信息不好”和“堆栈跟踪令人困惑/压倒性”。每年都在调查中排在第一的事实表明...检查调查...近50%的受访者(今年)。我想我至少要开始一个对话。

我将强调的一点(并且表示同意),因为每年的反应都是这样的

"如果简化的堆栈打印函数有用,那么这可以独立于核心完成" - 但这里是“核心”初学者最先接触的,也是这里的“核心”人们有抱怨。

希望初学者 - 以及那些教初学者的人 - 会提出具体的意见。
我仍然认为堆栈跟踪的最大问题就是工具在不应该显示它们的时候显示。当然,欢迎就特定问题提出更多问题(并且尽可能将它们保持隔离,这有助于投票和优先级)。

编辑了
当人们提供反馈时,如果能提供他们的编辑器/REPL设置的详细信息将很有帮助。

Emacs/CIDER在1.10的核心错误工作五年后仍然显示大的堆栈跟踪,并且它仍然是使用最广泛的编辑器设置...

(Alex提供了编辑器使用与优先改进区域的交叉表,清楚地表明Emacs/CIDER的堆栈跟踪与该编辑器的增加投诉不相关 -- 所有编辑器的错误消息约为50%的投诉)
...