[Date Prev][Date Next][Thread Prev][][Date Index][Thread Index]

Re: lexical-binding question



In [emacs-w3m:13517]
On Tue, 06 Aug 2019 10:47:56 +0200, Michael Heerdegen wrote:
> Katsumi Yamaoka <yamaoka@xxxxxxx> writes:

>> The following forms are utmost simplified model of the functions
>> that the above form uses:

--8<---------------cut here---------------start------------->8---
;; -*- lexical-binding: t -*-
(defun fn1 () ;; simplified `w3m-w3m-expand-arguments'
  (eval '`,charset))

(defun fn2 (charset) ;; simplified `w3m-rendering-half-dump'
  (ignore charset) ;; Silence the byte compiler.
  (fn1))

(defun fn3 (&optional charset) ;; simplified `w3m-rendering-buffer'
  (fn2 charset))
--8<---------------cut here---------------end--------------->8---

> CHARSET is a lexical variable in fn2 and fn3.  Its scope is limited to
> (textual) references in those functions.  The lexical binding is not
> visible in fn1 no matter what eval '`, tricks you try, because it's out
> of scope.  It would only work as you expect with a dynamically bound
> variable.

Yes, I believe that's absolutely true.  But my wonder is why the
current w3m.el code works.  Please try:

・Eval: (setq w3m-input-coding-system 'binary)
・Perform `edebug-defun' on the function `w3m-w3m-expand-arguments'.
・Run M-x w3m for visiting some web page.

Then, you will see '`,charset and `,charset, that the constant
`w3m-halfdump-command-arguments' defines, are substituted with
a certain charset value successfully, even though the value of
`charset' is not passed to `w3m-w3m-expand-arguments' explicitly.

While edebugging `w3m-w3m-expand-arguments', it is notable that
the form (boundp 'charset) returns t and (symbol-value 'charset)
returns a certain charset value.  Does it mean that `charset' is
not a lexical variable?  If it is true, why it happens, and why
it does not happen with the simplified forms (i.e., fn1~fn3)?

Before turning on lexical-binding, the w3m.el code was like this:

--8<---------------cut here---------------start------------->8---
;; -*- lexical-binding: nil -*-
(defun fn4 () ;; simplified `w3m-w3m-expand-arguments'
  (eval 'charset))

(defun fn5 (charset) ;; simplified `w3m-rendering-half-dump'
  (fn4))

(defun fn6 (&optional charset) ;; simplified `w3m-rendering-buffer'
  (fn5 charset))
--8<---------------cut here---------------end--------------->8---

(fn6 'big5) returns big5.  But it got to cause the void variable
error after turning on lexical-binding in w3m.el.  First I tried
was changing   charset   with   `,charset   in the value form of
the `w3m-halfdump-command-arguments' constant, and saw it made it
work.  Please don't ask me why I did so, it was just at random.

> You can either make `charset' special (that can even be done locally in
> the function) to reuse the old code, or you rewrite that stuff so that
> it's really lexical binding code.  Then w3m-halfdump-command-arguments
> would probably become a function `w3m-halfdump-get-command-arguments'
> that depends on an CHARSET argument, or something similar.

I think changing the constant to a function is TRT, too.  But I
don't want to do it before clearing this charset mystery. ;)

Thanks.