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

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

+3
错误

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

Slack上的讨论导致了许多关于异常和错误信息的具体痛点。我想在这里重点讨论的是提供一个对初学者友好的(pst)替代方案。

目前,(pst)在解密名称、消除“噪点”和缩减堆栈跟踪方面做了一些合理的尝试,但它仍然不能满足对某些异常理解有困难且在导航(Java样式的)堆栈跟踪方面有困难的初学者,尤其是与其他一些努力提供用户友好的错误信息和堆栈跟踪的语言相比。

来自Slack的一个例子

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

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

在REPL中打印出的异常还可以,但(pst)显示

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输入还是(pst)explain),将初学者难以理解的诸如class < whatever > cannot be cast to clojure.lang.IFn...之类的消息重写为易于理解的表述(例如Expected a function - found a < whatever>)。

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

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

我个人看到“无法进行类型转换”错误时,想看到“无法进行类型转换”的实际上值——而不是“无法将类Symbol转换为ISeq”,最好是看到“类Symbol ( `the-actual-symbol`) 无法转换为ISeq”,这样更容易确定打字错误或问题的位置。当然,许多不可见的类无法有意义地toString,但我想一些总比没有好。我明白这些错误来自Java方面,因此添加额外信息可能不是简单的事情,但它仍然很贴心。

另一个我经常遇到的问题是古怪且难以阅读的规范错误,这些错误要么需要很长时间通过肉眼解析,要么我必须使用一些库来为我进行美化的打印(为什么我需要使用库来使语言错误可读?)。最好有一个关于为什么“调用的defn不符合规范”的易读原因。可能在(不是代替)当前输出的基础上。
当你遇到这样的语法或规范情况时,请来这里提交一个问题!

ClassCastException异常是由jvm(在每一个函数调用时)产生的,因此我们无法增强这个特定案例(除非我们在每个转换周围发出更多的代码)。但是对于这些,如果你遇到一个令人困惑的错误,请来这里提交一个问题。
在REPL或测试中编写更多代码将非常好。

如果Clojure默认情况下将事物包装起来以便在REPL或测试时清晰显示Clojure语义而不是其实现细节,那我想这将是很好的错误消息。

1 答案

+4

这里至少有两个,可能还有更多不同的问题/想法,将它们分开将有所帮助。前串/hook想法似乎是正交的。

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

我认为“易于初学者学习”的表述并不准确,因为它没有提及任何问题。似乎如果堆栈跟踪更加清晰,那么它将对初学者和非初学者都有用,并且我们可以通过具体列出理解堆栈跟踪的挑战来得到帮助。我想起了...

  1. Clojure函数调用通常涉及每个调用2或3个框架。
  2. 匿名函数具有晦涩的名字。
  3. 在某些情况下,匿名函数由实现隐式创建。
  4. 用户调用宏,但堆栈跟踪处理展开的代码(你写的代码不等于你运行的代码)——这是错误消息和堆栈跟踪的基本问题。
  5. 宏代码经常创建gensym名称,这些名称成为类名。
  6. REPL基础结构在堆栈中。
  7. 工具基础结构在堆栈中(打印机,nrepl,中间件)。
  8. Clojure核心库和Clojure Java实现混合使用。
  9. 堆栈跟踪冗余显示文件名,除了Clojure ns或Java类。
  10. 行号与源代码不匹配。
  11. 惰性影响。

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

请记住,显示现实的另一种观点将始终与隐藏阐明为什么你首先查看堆栈跟踪的实际信息的风险形成对立。

如果简化堆栈打印器函数有用,则这可以独立于核心完成。特别是开发工具在这里具有非常好的地位。

by
我实话实说,我只是一条信息传递者。

除了ClassCastException,这似乎对初学者来说“经常出现”,他们需要更好的解释,我认为这些消息是可以的,我最初计划为ex-str hook创建一个分开的“求问” —— 因此,是的,我应该将其分开。

我不知道如何措辞这个问题——我也不觉得其他人能很好地把它表述出来。它总是只有“错误信息很差”和“堆栈跟踪令人困惑/令人难以置信”。事实上,它每年都是调查中的第一名,这反映出某种“需求”……检查调查……今年有近50%的受访者。我认为我至少可以开始一个对话。

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

“如果一个简化的堆栈打印功能是有用的,那么这可以与核心独立完成”——但是初学者最初接触的就是“核心”,人们在这里抱怨的也是“核心”。

希望初学者——以及那些教导初学者的人——能提供具体的建议。
by
我仍然认为堆栈跟踪的最大问题就是工具在不应该显示的时候显示了它们。当然,更多关于特定问题的提问都受欢迎(并且尽可能地保持它们孤立有助于投票和优先排序)。
by
编辑 by
当人们提供反馈时,如果能提供他们的编辑器/REPL配置的详细信息那就更好了。

Emacs/CIDER在1.10中对错误的核心工作已经过去五年了,它仍然会显示大堆栈跟踪,并且仍然是使用最广泛的编辑器配置...

(Alex提供了一个交叉表,展示编辑器使用与改进优先级之间的关系,很明显,Emacs/CIDER的堆栈跟踪与该编辑器的抱怨增加并无相关性——错误信息在所有编辑器中大约有50%的抱怨)
...