请在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函数,它接受与

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

例如,动态钩入ex-str可以允许社区提供的工具调整显示的异常消息(包括原始REPL输入以及),以便将初学者难以理解的邮件,如“class <anything>无法转换为clojure.lang.IFn...”重写为入门友好的语言(“期望函数 - 找到< anything>”)。

类似动态钩子可过滤堆栈帧,并将它们“打印”为字符串,从而为初学者提供更友好的输出。

在使用宏或语法错误(拼写错误)时,我经常遇到难以破译的错误。

个人来说,当我看到“无法转换为”错误时,我希望看到“无法转换”的实际值——而不是“类Symbol无法转换为ISeq”,而是“类Symbol (`the-actual-symbol`) 无法转换为ISeq”,这样更容易定位拼写错误/问题。当然,许多不透明的类无法有意义的转换为字符串,但我认为有点总比没有好。我明白这些错误来自Java方面,因此添加额外信息可能不是一件简单的事,但这仍然很好。

我还经常遇到一种奇特的、难以阅读的规范错误,这些错误或者需要很长时间通过肉眼解析,或者我必须使用一些库来进行美观输出(我为什么要使用库来使语言错误可读呢?)。如果能有个理由解释“调用defn没有符合规范”,那就更好了,可能是除了当前输出之外。
by
当你遇到这样的语法或规范问题时,请来这里提交问题!

ClassCastException异常是由jvm生成的(在几乎每次函数调用中都会发生),所以我们根本不可能增强这个特定案例(除非我们在每次转换周围生成大量代码)。但是对于这些情况,如果你遇到一个令人困惑的错误,请来这里提交问题。
by
在REPL或测试中围绕那个发送更多的代码会更好。

如果Clojure在REPL或测试时以默认运行模式下对事物进行包装,以便它可以清楚地以Clojure语义而不是其实现细节显示错误,我认为这对于错误消息来说会很好。

1 答案

+4

这里至少有两个,可能更多,不同的问题/想法,将它们分开会更恰当。前缀/钩子想法似乎是正交的。

严肃的问题——如果错误消息是好的(你说它是这里的),而且工具从未显示堆栈跟踪,为什么这是一个初学者问题?错误消息尝试显示源错误(考虑到宏的约束)的合理位置。

“初学者友好”这个框架可能并不恰当,因为这与问题无关。如果堆栈跟踪更加明确,那么它将对初学者和非初学者都很有用,并且具体列出理解堆栈跟踪的挑战将帮助到我们。不假思索...

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

简化堆栈跟踪的功能函数需要清楚地说明哪些这些问题或其他潜在问题实际上是重要的。其中一些相对简单,而另一些则非常困难。

请注意,展示现实的一种替代视角将与隐藏实际信息的风险相冲突,这些信息可以阐明你为什么首先看堆栈跟踪。

如果简化堆栈打印功能是有用的,那么这可以在核心之外独立完成。特别是开发工具在这方面处于非常好的位置。

坦白说,我只是传话的人。

除了“ClassCastException”经常出现,对于需要更好解释的初学者来说,“ClassCastException”似乎是常见的,我认为消息是好的,我最初打算为ex-str钩子创建一个单独的“ask”——所以,是的,我应该将其分开。

我不知道如何措辞这个问题——我也没有看到其他人提出得很好。它总是不过是“错误信息很糟糕”和“堆栈跟踪令人困惑/压倒性”。每年它在调查中都排在第一,这足以说明从...检查调查...近50%的受访者(今年)存在着某种“需求”。我认为我至少可以开始一个对话。

我要强调的一点(并且同意这一点),因为每年我都听到这样的回应

“如果一个简化的堆栈打印函数是有用的,那么这可以独立进行”——但这首先是“核心”,初学者接触到的,也是在这里人们抱怨的地方。

希望初学者——以及对初学者进行教学的的人们——能够就具体细节给出反馈。
by
我继续认为,堆栈跟踪的最大问题就是工具在它不应该显示的时候显示了。无论如何,更多的关于特定问题的问题总是受欢迎的(并且尽量使它们孤立,有助于投票和优先级)。
by
编辑于 by
是的,如果人们在提供反馈时能提供他们编辑器/REPL设置的详细信息,那将很有帮助。

CIDER/CIDER在一个多核工具在错误处理方面做了大量工作之后五年了,仍然显示出大型的堆栈跟踪,并且它仍然是使用最广泛的编辑器设置...

(Alex提供了一个编辑器使用与改进优先级交叉表格,很明显,Emacs/cider的堆栈跟踪与该编辑器的投诉增加不相关——在不同的编辑器中,错误信息大约占了投诉的一半)
...