emacs-devel
[Top][All Lists]
Advanced

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

Re: cl-eval-when -- A workaround for recursive require?


From: Zhu Zihao
Subject: Re: cl-eval-when -- A workaround for recursive require?
Date: Sun, 01 May 2022 01:09:34 +0800
User-agent: mu4e 1.6.10; emacs 27.2

Hi Stefan, I'm very happy to see your answer!

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> There's nothing special about `cl-eval-when` for cyclic dependencies.
> Some parts of `cl-eval-when` rely on ugly hacks, but I don't think it
> makes much difference here.

Oh, it's worse... sounds that Magit is playing with black magic code. 

I found some design of `cl-eval-when` is not straightforward. I did some
experiment to learn about it.

```
;; bar.el

(require 'cl-lib)

(cl-eval-when (eval)
  (message "I'm running on eval!"))
(cl-eval-when (load)
  (message "I'm running on load!"))
(cl-eval-when (compile)
  (message "I'm running on compile!"))

;; Run `(byte-compile-file "bar.el")`
;;  => I'm running on compile!

;; Run (load-file "bar.el")
;; => I'm running on eval!

;; Open the bar.el file and run `M-x eval-buffer`
;; => I'm running on eval!

;; Run byte compile and `(load-file "bar.elc")`
;; => I'm running on load!

;; Open the byte-compiled file (bar.elc)
;; => (byte-code "\300\301!\210\302\303!\207" [require cl-lib message "I'm 
running on load!"] 2)

;; Eval the byte-code above
;; => I'm running on load!
```

The `:load-toplevel` means the content of the top-level block will be
available in bytecode. But it doest NOT eval in the plain S-exp file.
And on the contary. It looks weird because IMO `:load-toplevel` is the
timing we call `load` to load Elisp code from file, regardless bytecode
or S-exp file. Is this intened design or a long lasting bug? Because
`info (cl) "Time of Evaluation"` says:

The ‘cl-eval-when’ acts like a ‘progn’ if ‘eval’ is specified, and like
‘nil’ (ignoring the body FORMS) if not.

If only `eval` is specified. the forms will be discarded in
byte-compiled file. Maybe the `(cl-eval-when (load eval) ...)` should be
the equivalent to `progn`.


From the point of my view, `cl-eval-when` sucks and hurts the mental of
code reader and writer. There's many combination for `cl-eval-when` but
only fews are useful for coding, and these usefule combinations can be
replaced by `eval-when-compile` and/or `eval-and-compile`. This two
compiler intrinsics help the code more robust in differnt evaluation
context whether it's byte-compiled or plain S-exp.

I suggest we can mark `cl-eval-when` as deprecated in favour
`eval-when-compile` and/or `eval-and-compile`. 

> Often one of the best tools for that is to rely on autoloads instead of
> `require` for some functions, and the better way to do that is to use an
> "internal" autoloads file (i.e. one that's separate from the
> `<pkg>-autoloads.el` loaded at startup and that's only loaded when the
> package is actually used).
>
> See lisp/**/*-loaddefs.el for examples of such "internal"
> autoloads files.
>
> We don't have great support for auto-generation of such files, tho, so
> sometimes it requires manual work to set it up (if you search for
> `;;;###` in `lisp/Makefile.in` you'll see examples of what I'm
> referring to).

IMO the package.el is quite limited and it may not fit the development
of some Emacs packages (e.g. packages with dynamic module require
compiling, or packages requires preprocessing to locate some resource)
But this is another topic.  

-- 
Retrieve my PGP public key:

  gpg --recv-keys D47A9C8B2AE3905B563D9135BE42B352A9F6821F

Zihao

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]