EIEIO 是 Emacs Lisp 面向对象的其中一种实现,在旧有的 Common Lisp 兼容包上改进的(这个兼容包本来就有面向对象系统)。其他还有一些轻量面向对象系统,比如 Wanderlust 和 w3m 用的是 FLIM 的基于 Pratical Common Lisp 中实现的简易 CLOS 的 luna;参照了 Smalltalk 的 EOOPS。
EIEIO 和 Cedet 的关系类似于 Wanderlust 和 FILM,本身其实是同一个项目根据库和功能拆开了写,只是也有别的项目用这个库。
从这可以差不多看到在 Emacs Lisp 中用面向对象的基本是 CL 用户。
按照 CL 的习惯,数据结构很多会用 class 来实现。主要是为了扩展性和自动化。类似于 C++ 用 class 而不是 struct 的原因。
2 个赞
看完后的感想是,现在不是 Lisp 砖家怕是都 hack 不动 Spacemacs 了。
潜台词就是: 年轻人先来学一遍 Pratical Common Lisp 再来用 Emacs 吧。
本来在 Emacs 扩展都以单独的包发布的时候,想 Hack 了可以直接 C-h f 看看源代码然后吐槽一下风格,大部分时候代码逻辑都是比较清晰的。修改用 advice,才是 Emacs 比较推荐的做法。
大幅引入抽象以后,对于作者来说写是可以少写了,不是对项目特别熟的怕是动不了了。没有面向对象编程和 Lisp 经验的人连某个功能在哪里实现的都找不到。算是做绝了点。
我之前看spacemacs的时候也是感觉抽象很多,导致我看不懂配置。这下怕是更多了。
然而在 Emacs Lisp 中,用 struct 的情况占多数。
struct 也是可以扩展的:
(cl-defstruct person name (age 0) sex)
(cl-defstruct (astronaut (:include person (age 45)))
helmet-size
(favoite-beverage 'tang))
(setq joe (make-person :name "Joe"))
(setq buzz (make-astronaut :name "Buzz"))
改为 class:
(defclass person ()
((name) (age :initform 0) (sex)))
(defclass astronaut (person)
((age :initform 45)
(helmet-size)
(favoite-beverage :initform 'tang)))
(setq joe (person :name "Joe"))
(setq buzz (astronaut :name "Buzz"))
如果是我,可能会这样定义成员函数:
(defmethod walk ((p person))
(message "walking on earth"))
(defmethod walk ((p astronaut))
(message "walking in space"))
(walk joe)
(walk buzz)
在 helm 中更多是这样的:
(defclass person ()
(;;...
(walk
:initarg :walk
:initform (lambda ()
(message "walking on earth")))))
(defclass astronaut (person)
(;;...
(walk
:initarg :walk
:initform (lambda ()
(message "walking in space")))))
(funcall (oref joe :walk))
(funcall (oref buzz :walk))
可能这样更方便迭代吧。
Spacemacs —— 重新发明了 Emacs 配置
find-function只能跳转到文件开头,无法跳到定义处,很尴尬
不记得是什么函数……因为都是用spacemacs doom-emacs快捷键的
我都是C-h f 然后鼠标点就能直接跳转函数了。记得是describe function
不过往好处想的话,反正新手已经看不懂spacemacs了,如果改写能让spacemacs效率翻倍功能完善配置清晰也挺好的。
我开始hack spacemacs的时候都是从在user-config里写小片段开始,后来干脆开始自己的配置了,从头到尾没有看spqcemacs实现。中间弄自己的layer的时候看过spacemacs layer的配置。
是指用宏批量生成函数然后find-function
找不到的那些么?
如果是 (defmethod foo () ...)
这种形式,出来的函数名仍然是 foo
,还是能跳转的。 find-function
是先切换到定义所在的文件,然后正则表达式全文查找,所以只要往 find-function-regexp{,-alist}
添加规则就能匹配到。
如果定义 (definitfun foo () ...)
,然后生成的函数名 init//foo
,这种就不太好办了。
defmethod 问题在如果分了好几个文件就麻烦了。
et2010
17
double dot 这个分支好像也被抛弃了,现在repo owner最新的 commit 在 moon 分支上。只是也有快一个月没更新了。感觉作者在酝酿什么大招,而且不实现就暂时不合并任何 PR。
是这样吗?如果是就太可惜了,本来以为可以一直发展下去的。最近确实一直没什么动静了。
感觉 advice 机制,就是从clos得到灵感的,个人感觉,基于广义函数的面向对象比大多数人熟悉的面向对象,更符合直觉