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

欢迎!有关如何使用本站的更多信息,请访问关于页面。

0
tools.namespace

我在我们的代码库中找到一个有趣的 issue,一些带有标签的字面量似乎违反了最小惊讶原则。

我们创建了一些纯数据过程描述,包括来自在 data_readers.cljc 中声明的自定义标签字面量读取器的 defrecord 对象,并让这些 defrecord 对象参与到协议中。一切一直工作得很顺利,直到我遇到了这个问题。

有人将这些标签字面量之一放入了 def(一开始这似乎是合理的)

(def foo #ctx/event-path [:blah])

这没有问题...直到 c.t.n.r/refresh 被调用,在此之后一切开始出现问题

结果发现,defrecord 对象 foo 中的类已经过时(很可能是由于在 data_readers.cljc 中声明的标签字面量解析器引起的命名空间依赖不被 tools.namespace 所识别,因此命名空间被重新编译且顺序混乱),因此不再参与协议。

tools.namespace 应该能够识别由 data_readers.cljc 诱导的依赖吗?或者这超出了它的能力范围?

2 个答案

0

我认为这里的一个重要考虑因素是,拥有一个 data_readers.cljc 文件并不会自动加载或要求读取函数命名空间。您的程序仍然需要在读取映射到该读取函数的标记文字之前负责要求包含读取函数的命名空间。这对原始源文件中的标记文字来说通常很麻烦,也许应该对此进行更改,但这正是目前的工作方式。

考虑到这一点,包含 def 的命名空间隐式依赖于读取命名空间才能被读取,正确的做法是在该命名空间的 ns 定义中明确这种依赖。如果您这样做,就不会有“由 data_readers.cljc 引起的依赖”,只有在该命名空间定义中已经明确显示的依赖,您就不会遇到这个问题。

因此,我认为这并不是 tools.namespace 需要的功能(考虑到 Clojure 的当前实现)。

嗯,这是至关重要的一点 @alexmiller —— 这意味着我之前对为什么在 `c.t.n.r/refresh` 之后事物失败(但在生产环境中却不会)的理解是错误的。

回到起跑线。
–1

我最初的反应是“嗯,c.t.n.r/refresh 可以破坏各种东西,我常常看到初学者在使用 reload/refresh 的工作流程时遇到麻烦……”这就是为什么我总是跳入每一个出现 reload/refresh 的对话,并说“别这样做!”

在我看来,这仅仅是对由最初不理想的 REPL 工作流程引起的问题的一个不良解决方案。不要用创可贴,而要鼓励更好的 REPL 工作流程。

是的,我知道 Clojure 中的一些部分实际上可以生成 Java 类,这可以在 REPL 中使生活变得困难——但 c.t.n.r/refresh 无论如何都不能解决所有这些问题(我认为这会导致人们停止思考这些问题)。

我真心希望核心团队能够就处理记录和 Clojure/Java 交互的其他领域的 REPL 友好方式提供建议。我看到了一些建议,诸如使用生成的函数而不是直接引用记录类型可以有所帮助,但我认为,关于如何组织需要更好指导的记录的协议扩展仍有一些问题。

https://github.com/aredington/clojure-repl-sufficient-p这个有趣的仓库中,突出了一些当前REPL实现中的不利因素,如果在有人愿意添加它的情况下,这个特殊情况可以包括在内。我特别喜欢这个仓库在组织某些活动方面的预期方式。
如果这个仓库实际上解释了具体的问题是什么以及如何减轻这些问题,那将会是一个非常有用的仓库。源文件和单个测试文件在目的上都非常不透明。

只有在comp/wrapper源文件内部,它才会尝试显示REPL友好的等效版本。
@sean 对于我的情况,我找到了一种构建记录的方法,使得记录的协议实现能够在协议类由于依赖顺序而被重新加载的情况下不受影响——通过使用`:extend-via-metadata`。这并不太优雅——使用记录类型来调度print方法以将记录序列化为tagged-literal,并使用元数据实现协议,但它是有效的

(不幸的是,这只能在clj上工作,并在cljs上遇到无法理解的编译错误,所以我现在已经放弃了使用完全序列化往返进行自定义标签化的整个想法)

@sean 我对你的“不太理想的”和“更好的”REPL工作流的描述很感兴趣,你能提供更详细的信息吗?可以链接吗?
对于这个非答案,我有点失望。一个更具建设性的看法会是“是的,库中确实存在缺陷,并且可以修复”。

如果tools.namespace中的bug被修复,我们就不会在谈论它会“打破各种东西”了。

反复鼓励人们不要使用库是一种自我实现的预言——在某些时候,没有多少人会想要在tools.namespace上编写代码,受到FUD(恐惧、不确定和怀疑)的指导。这 perpetuates the bugs。

我希望有人能承担tools.namespace的开发。我肯定会支持我使用的分支。我目前没有时间改进官方的t.n。
有点过分戏剧化,vemv——我并不是在阻止人们使用tools.namespace,而是在阻止refresh。我认为问题出在工作流程上,而不是库本身。
不管戏剧化与否,我对反复对一种特定的方法(可能有花哨的名字,但 nothing more than 'automation')的抨击感到困惑。在我们的社区中通常不会看到这种做法,如https://clojure.org/community/etiquette中所反映的那样。
请将讨论集中在手头的問題上。
...