semantic/wisent中存在可能导致闭包捕捉失效的变量

局部变量不被闭包捕捉的凶手找到了 @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 个赞

Elisp也可以的。代价是byte-compiler报警

Lexical argument shadows the dynamic variable c
1 个赞

有点物理/科幻的味道 :thinking:

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 个赞

置顶就太夸张了,这是Emacs的问题,又不是站务问题。不过可以考虑收集起来做个Elisp 100黑之类的。

当然不会真的置顶,只是情绪的表达。

我决定在修复编译 warning 的时候,把这条拎出来,单独做一次提交并打上 tag。

可以投稿emacs horror