可扩展性:“100% Lisp”谬误
Extensibility: The "100% Lisp" Fallacy

原始链接: https://kyo.iroiro.party/en/posts/100-percent-lisp/

使用“纯 Lisp”扩展 Emacs 提供了强大的自定义能力,但也带来了显著的挑战。虽然理论上允许修改*任何*代码,但实际操作表明,这涉及到一个复杂的依赖和内部函数网络。简单的覆盖,例如更改 Org-mode 中的 HTML ID 生成,通常需要修补多个函数,因为存在被绕过的调用和内部实现细节(用双破折号表示)。 像 `el-patch` 这样的工具可以促进更深层次的修改,但需要持续维护以避免 Emacs 更新导致的问题。这突出了核心困境:强大的封装限制了自定义,而完全暴露则危及兼容性。 作者认为 Emacs 当前不完善的跨语言隔离和 API 是*有益的*。一个真正“纯 Lisp”且完全可扩展的 Emacs 将会产生维护噩梦,任何更改都可能破坏现有的工作流程——这也是他们 Emacs 克隆项目可行的一个关键原因。

黑客新闻 新的 | 过去的 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 可扩展性: “100% Lisp” 的谬误 (iroiro.party) 8 分,by todsacerdoti 35 分钟前 | 隐藏 | 过去的 | 收藏 | 讨论 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

Compared to extending via workarounds, extending in “pure Lisp” can be both easier and harder, as we are still bounded by coding conventions and existing code, and one cannot possibly extend everything without breaking some of them.

Let’s start by overriding a single function. For example, when exporting Org-mode files to HTML, Org-mode defaults to generating random HTML ID anchors. To change that, you just override the org-export-get-reference function that generates the IDs, right?

(advice-add #'org-export-get-reference :around #'org-html-stable-ids--get-reference)

Oh no! It turns out that, sometimes Org-mode directly calls org-html--reference, bypassing our override. That means we also need to redirect org-html--reference:

(advice-add #'org-html--reference :override #'org-html-stable-ids--reference)

Problem solved? No. Conventionally, Emacs Lisp code uses double dashes to tell the users “this function is internal”, as is in the org-html--reference name. Yes, by being free to extend any part of the editor, you are free to modify any internal functions or states, in a way that may or may not be problematic under specific circumstances, with code that can be broken in any future updates.

And it’s not the end of it. The el-patch package allows you to apply “patches” on most any Lisp code to modify behaviours nested deep inside a function:

;; Original function
(defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror nil 'nosuffix))

;; Patching
(el-patch-feature company-statistics)
(with-eval-after-load 'company-statistics
  (el-patch-defun company-statistics--load ()
                  "Restore statistics."
                  (load company-statistics-file 'noerror
                        ;; The patch
                        (el-patch-swap nil 'nomessage)
                        'nosuffix)))

;; Patched version
(defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror 'nomessage 'nosuffix))

Luckily, el-patch provides el-patch-validate so that you can worry less about your patches going ineffective or unexpectedly destructive. But you still need to maintain all your patches if anything goes wrong.

Any extensible system is not void of these problems. If you impose strong enough encapsulation, then eventually something can’t get customized; if you expose everything, well, good luck keeping backward compatibility (as the system maintainer) or forward compatibility (as the user doing your modifications). By making it possible to “extend any part of the editor,” you are literally making any part of your code unextensible, and now “every change breaks someone’s workflow.”

workflow_2x.png

Emacs’s cross-language isolation/API might not be perfect, but I’m very grateful for it. If Emacs were written in pure Lisp code and anything is extensible, my work-in-progress Emacs clone couldn’t be remotely possible (because we do want to rid some of the spacebar heating problems while keeping some compatibility).

联系我们 contact @ memedata.com