Closed akater closed 4 years ago
header argument load is just an optional alternative to the original common lisp feature, It is provided so we can insert codes for different purpose, but you can still use original common lisp feature by the dispatcher #+ or #-.
A programmer can use eval-when in a code block directly, so I don't think it's a necessary feature for literate programming,unless it can give us some additional benefit.
Jingtao Xu notifications@github.com writes:
header argument load is just an optional alternative to the original common lisp feature, It is provided so we can insert codes for different purpose, but you can still use original common lisp feature by the dispatcher #+.
I didn't study the implementation, sorry. What feature is it an alternative to? What is this original feature do you have in mind that could go to #+?
A programmer can use eval-when in a code block directly, so I don't think it's a necessary feature for literate programming,unless it can give use additional benefit.
The primary benefit is interface consistency. You implemented a reader
macro. All such introduce special syntax. Your syntax effectively allows
to conditionally evaluate parts of source code, or ignore them. (Or
maybe, to read or not to read them; more on this later.) I believe it
would be better if this syntax was consistent with the existing syntax
that allows to conditionally evaluate parts of code, or ignore them. In
Common Lisp, this syntax is eval-when
. I suggest to reuse the existing
name and its feature set which is a superset of the existing one—which
is not surprising: eval-when
serves the same purpose but it had
absorbed decades of experience. You think nobody would ask for :compile yes
in addition to :load no
? I believe it is totally natural to want
one when you already have the other.
One additional benefit is convenience in changing evaluation mode of
blocks of code (as opposed to individual forms): I could imagine elisp
function wrap-defun-in-eval-when
but selecting multiple top-level
forms to wrap would be far less convenient while in org mode they are
already seleched by the block. In contrast, I can easily imagine
:eval-when
switcher for block at point that works like
dired-do-chmod
—which is both much more convenient and more
straightforward to implement than (un)wrapping whole forms (or, worse,
collections of forms) in full-blown eval-when
expressions. E.g. ‹key for ob-lisp-do-cheval› ce RET
could change the header to :eval-when compile execute
.
Another additional benefit is, less noisy diffs.
I can see how I can be wrong about the following detail: depending on
how you implemented a reader macro, there might be a slight difference:
with traditional eval-when
, the form is always read; with header
argument :eval-when
form(s) might not even be read. It thus would be
more precise to call it :read-when
, then. But I'm not certain on this;
:eval-when
seems fine to me even if it actually means read-when
,
unless we have to deal with tangling (more on this below).
To share some personal experience, my use cases for :load no
are
blocks that contain examples and, more generally, tests. I never use
:load yes
as I never tried to override this default value. :load no
is used both in examples to be evaluated interactively, and in examples
to not be evaluated interactively, in which latter case it is coupled
with :eval never
.
With support for :eval-when
and some non-intrusive patches to Org,
:load no :eval never
could be replaced with :eval-when never
or
maybe with :eval-when ()
or :eval-when nil
for further consistency
(we could support all of those, of course)
plain :load no
would then correspond to :eval-when execute
. It is
less cryptic to label examples this way than how I have to do it now,
saying “don't load this” and not saying what actually could (should)
be done to the block.
Last but not least, I think it's better to be able to use one single
parameter rather than two different parameters :eval
and :load
that
have the same scope, are thus interdependent and have thus to be
re-adjusted in concert. The ability to write :eval-when compile
would
be a very nice consequence. Tangling is of no interest to me (why would
it be of intrest to any user of literate-lisp
?) but objectively,
tangling is an operation on a file, on par with loading a file and
compiling a file. It thus makes total sense to be able to write
:eval-when tangle
for code to be evaluated when tangling the
file. Traditional :tangle yes
would then however certainly correspond
to :read-when tangle
, so here we must make this distinction I
discussed above.
What are your usage patterns for :load no
and :load yes
? What we're
doing is quite experimental so different people could discover quite
different practices.
Regarding your comment that eval-when
is accessible to programmers anyway—well, let
form is also accessible to programmers, and yet Org does provide :var
header argument. Looks like it is not supported by Lisp backend but that's the issue with the backend.
The next interesting feature of literate-lisp is the web syntax, so we can organize codes as blocks, instead of just one, for example this: https://github.com/jingtaozf/literate-lisp/blob/web/literate-lisp.org#web-syntax
I agreed that different people could discover quite different practices and we can use one header argument instead of two here.
A patch with good design is welcome.
Please re-open this issue if you still have questions about it.
I suggest to provide
:eval-when
header argument as an additional feature, and maybe retire:load
header argument altogether.Example:
should be read as
In general,
:eval-when compile
:eval-when compile load
:eval-when load
should wrap forms in the correspondingeval-when
.The default (absence of
:eval-when
) should likely correspond to:eval-when load
.There is no need to provide support for
:execute
here, due to semantics of:execute
and the fact that:eval-when
would not affect org-babel evaluation. However, it might be appropriate to blindly translate:eval-when whatever and-more
intowhile treating
compile
andload
as special cases.When it comes to preventing evaluation, several approaches come to mind:
:eval-when never
:eval-when ()
The first one comes from Emacs Lisp tradition (cf.
:eval never
), the second one—from Common Lisp.I also believe that not ignoring the block in the presence of
:eval never
is a bug.Using just
:eval
(and thus extending the existin org header) is OK too but I believe it would be better to separate those as they are meant for different functions, namely:eval
andcompile-file
.