cireu
1
局部变量不被闭包捕捉的凶手找到了 @CEDET
以前Emacs没词法作用域,这样用把用来let-bound使用的变量defvar声明防止byte-compiler报警方式还问题不大。但Emacs24引入词法作用域后,这样声明变量会把变量标记为动态绑定(向后兼容)。如果你恰好用了和他们同名的本地变量,那么你的本地变量将会从闭包中逃逸
试比较
;;; -*- lexical-binding: t; -*-
(defvar c)
(funcall (let ((c 3))
(lambda () (+ c 2))))
;;; -*- lexical-binding: t; -*-
(defvar c)
(funcall (let ((e 3))
(lambda () (+ e 2))))
后者可以正常加载执行,而前者加载过程中会报错
Load error for /home/chino/tmp/test-leix.el:
(void-variable c)
具体到这个例子,规避的方法如果引用了wisent就不要起这三个名字的局部变量。
另外令我不解的是wisent.el末尾写了
(provide 'semantic/wisent/wisent)
然而我照抄这个symbol却不能require,最后还是用的(require 'semantic/wisent)
1 个赞
⋊> ag '\(provide \'semantic/wisent' ~/emacs-2019-06-26-f0151e17d296bfdeb1ca3f002c9b430c8302a6e7/ -G\.el\$
...
~/emacs-2019-06-26-f0151e17d296bfdeb1ca3f002c9b430c8302a6e7/lisp/cedet/semantic/wisent/wisent.el
476:(provide 'semantic/wisent/wisent)
~/emacs-2019-06-26-f0151e17d296bfdeb1ca3f002c9b430c8302a6e7/lisp/cedet/semantic/wisent.el
342:(provide 'semantic/wisent)
ISLISP 和 EuLisp 标准决定取用动态绑定需要显式用 (dynamic var)
,估计有这方面的考量。
Common Lisp 可以写
(defun foo (*standard-input*)
...)
;; where *standard-input* is special
;; 相当于
(defun foo (stream)
(let ((*standard-input* stream))
...
1 个赞
cireu
4
Elisp也可以的。代价是byte-compiler报警
Lexical argument shadows the dynamic variable c
1 个赞
刚刚也掉进了这个坑里。
开始怎么也没想到问题出在这个函数末尾的参数名称上:
(defun separedit--enclosed-comment-p (&optional comment-beginning comment-end)
"Determine if the comment from COMMENT-BEGINNING to COMMENT-END is enclosed."
(and (save-excursion
(if comment-beginning
(goto-char comment-beginning))
;; ...
)
(save-excursion
(if comment-end
(goto-char comment-end))
;; ...
)
t))
编译的时候一直告警:
⋊> make compile
emacs -batch -L . -l cask-bootstrap.el -f batch-byte-compile separedit.el
In toplevel form:
separedit.el:571:1:Warning: Lexical argument shadows the dynamic variable
comment-end
我觉得本帖应该置顶,或者搞个 emacs-sucks
标签来汇集所有类似的奇葩问题。
1 个赞
cireu
7
置顶就太夸张了,这是Emacs的问题,又不是站务问题。不过可以考虑收集起来做个Elisp 100黑之类的。
当然不会真的置顶,只是情绪的表达。
我决定在修复编译 warning 的时候,把这条拎出来,单独做一次提交并打上 tag。