问题陈述
Clojure的REPL能够参数化其功能几乎各个方面,包括未捕获异常的打印方式。在当前实现中,这些自定义钩子作为参数传递并通过闭包执行,意味着一旦REPL开始运行,它们不能被更改。
许多开发工具想要覆盖REPL如何处理未捕获的错误。有用的自定义示例包括(但不限于)
- 格式化的异常信息(包括空格和ANSI颜色)
- 某些类型异常的替代表示(例如,Spec错误)
- 进入图形交互模式以更好地检查ex-data。
目前,这种类型的自定义必须在REPL启动之前应用,这意味着更改REPL显示错误需要来自(或Leiningen之类的第三方工具的)插件的支持。
替代方案
<BR/>
1. 不采取任何行动。
需要第三方工具来创建REPL中的自定义异常处理。这些工具有不同的技术来完成这项工作
- nREPL可以拦截线上的异常并通过中间件传递
- Leiningen插件更改了{{clojure.main/repl-caught}}的根绑定。
- Boot允许用户构建一个任务来调用{{clojure.main/repl}}并带有所需的参数。
用户将继续根据自己的工具偏好选择其中之一。
优点
1. 不会对现有代码造成任何影响或更改。
权衡
1. 工具将继续实施各自不同的、有时是黑客般的技术来打印自定义异常。
2. 旨在提供替代异常处理的任何库都将绑定到特定的启动工具。
- 使REPL异常处理器动态重新绑定
如果REPL异常处理器是一个动态的线程局部变量,用户和库可以改变当前运行的REPL的行为。
优点
1. 用户和库可以自由覆盖异常的打印方式,不管Clojure是如何启动的。
2. 完全向后兼容现有工具。
权衡
1. 库的作者可以提供“不良”或推理不充分的错误打印机。这仍然可以通过启动工具实现,但由于库的屏障更低,所以更加容易。
附带的补丁实现了此选项。
- 鼓励用户启动新的REPL
在许多Clojure环境中,可以从另一个REPL中显式启动REPL。此子REPL可以具有所需的:caught钩子。
优点
1. 不会对现有代码造成任何影响或更改。
2. “函数式纯”,并且与当前REPL的明显设计相一致。
权衡
1. 在Clojure开发者中,存在一个非平凡的子集,他们并不确切知道REPL是如何工作的。这很可能会让他们感到困惑,或者增加认知负荷。鉴于这部分初学者/中级开发者正是最初预期通过增强错误消息来帮助的对象,这个解决方案是适得其反的。
2. 无论好坏,许多现有的和广泛使用的工作工具都不支持这一点。例如,在nREPL中完全不起作用。然而,即使是功能最简单的命令行REPL的表现也会变差;发送EOF(无论是意外还是其他原因)总会杀死次级REPL,而没有任何反馈说明发生了什么。