unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* cl-block less lexical than expected
@ 2021-12-30 18:12 Robin Tarsiger
  2021-12-30 18:15 ` Robin Tarsiger
  2021-12-30 18:50 ` Stefan Monnier
  0 siblings, 2 replies; 5+ messages in thread
From: Robin Tarsiger @ 2021-12-30 18:12 UTC (permalink / raw)
  To: Emacs-Devel List

Greetings.

Today I was poking around with elisp and decided to look at the
definitions of cl-block and cl-return-from. These are predictably
described in the elisp manual as using lexical tags along the lines
of how actual-CL block and return-from work. However, the way the
macros are implemented doesn't line up with this; they do a static
transformation on the tag name and then intern the result for use
with catch/throw, and that yields dynamic semantics:

   (defun tmp/cl-block-test-1 ()
     (cl-block foo
       (cl-return-from foo 'ok)
       'not-reached))

   (defun tmp/cl-block-test-2 ()
     (cl-return-from foo 'bad))

   (defun tmp/cl-block-test-3 ()
     (cl-block foo
       (tmp/cl-block-test-2)
       ;; Necessary to avoid the catch being discarded.
       (cl-return-from foo 'correct)))

   (tmp/cl-block-test-1)
   ==> ok ; This is fine.

   (tmp/cl-block-test-2)
   ==> <signals error> ; Also okay.

   (tmp/cl-block-test-3)
   ==> bad ; But the foo block isn't actually lexical!

I have to think that since catch and throw both take evaluated
expressions for their tags, a more suitable implementation might
do a static transformation to choose an out-of-the-way lexical
_variable_ name which would then be let-bound to a gensym during
the body. cl-return-from could then try to evaluate the variable
to get the tag; the warnings/errors for bad tags would be awkward
to read, but at least the semantics would be correct. An unbound
tag variable would also be warned about during byte-compilation.

Thoughts?

-RTT



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cl-block less lexical than expected
  2021-12-30 18:12 cl-block less lexical than expected Robin Tarsiger
@ 2021-12-30 18:15 ` Robin Tarsiger
  2021-12-30 18:50 ` Stefan Monnier
  1 sibling, 0 replies; 5+ messages in thread
From: Robin Tarsiger @ 2021-12-30 18:15 UTC (permalink / raw)
  To: emacs-devel

Robin Tarsiger wrote:
> cl-return-from could then try to evaluate the variable
> to get the tag; the warnings/errors for bad tags would be awkward
> to read, but at least the semantics would be correct.

Slight correction---they would be correct _provided that_ lexical-binding
were in use for the let. However, I gather having it on almost all the time
is becoming the norm (and maybe the macros could warn if it's off).

-RTT



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cl-block less lexical than expected
  2021-12-30 18:12 cl-block less lexical than expected Robin Tarsiger
  2021-12-30 18:15 ` Robin Tarsiger
@ 2021-12-30 18:50 ` Stefan Monnier
  2022-01-04 19:29   ` Robin Tarsiger
  1 sibling, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2021-12-30 18:50 UTC (permalink / raw)
  To: Robin Tarsiger; +Cc: Emacs-Devel List

> I have to think that since catch and throw both take evaluated
> expressions for their tags, a more suitable implementation might
> do a static transformation to choose an out-of-the-way lexical
> _variable_ name which would then be let-bound to a gensym during
> the body. cl-return-from could then try to evaluate the variable
> to get the tag;

Sounds good.  As you noted, this was not an option when these macros
were written because of the need for statically scoped variables.

> the warnings/errors for bad tags would be awkward to read, but at
> least the semantics would be correct.

By carefully choosing the names we use that shouldn't be too bad.


        Stefan




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cl-block less lexical than expected
  2021-12-30 18:50 ` Stefan Monnier
@ 2022-01-04 19:29   ` Robin Tarsiger
  2022-01-04 20:11     ` Eli Zaretskii
  0 siblings, 1 reply; 5+ messages in thread
From: Robin Tarsiger @ 2022-01-04 19:29 UTC (permalink / raw)
  To: Emacs-Devel List

I wrote:
 > I have to think that since catch and throw both take evaluated
 > expressions for their tags, a more suitable implementation might
 > do a static transformation to choose an out-of-the-way lexical
 > _variable_ name which would then be let-bound to a gensym during
 > the body. cl-return-from could then try to evaluate the variable
 > to get the tag;

Stefan Monnier wrote:
> Sounds good.  As you noted, this was not an option when these macros
> were written because of the need for statically scoped variables.

So I've been experimenting a little with modifying cl-macs.el to make
this happen. I think I have it about right, but here's what I've found
that's tricky:

   - cl--block-wrapper currently assumes it's receiving exactly a form
     produced by cl--block and invasively unwraps it, so they have to
     be kept in sync. This isn't too bad when it's just a catch form,
     but the new form is much more highly nested.

     I imagine having cl--block-wrapper do most of the expansion itself
     and be implemented as macro+cmacro rather than passthrough+cmacro
     would be cleaner here?

   - The new form is more highly nested not just because of the let to
     keep the tag in a variable, but because of an unwind-protect used
     to clear out the variable when the body is exited. This is so that
     lambdas that cl-return-from the enclosing block function properly
     when called while the block is executing, but can _not_ erroneously
     return from a separate activation of the same block if called after
     the original activation of the block has exited. Instead, they will
     wind up throwing to a dummy tag and signaling a recognizable error
     thereby.

     Naturally, the existing code misbehaves in this scenario as well.

   - I currently have cl-block warn if lexical-binding is nil. I did a
     quick pass over the Lisp files included with Emacs to make sure
     all files with cl-block-alikes used lexical-binding, but I don't
     know what impact this would have on external packages.

   - It would be nice to have cl-return-from warn if it doesn't see the
     name in the list of extant blocks that the cl--block-wrapper cmacro
     already uses to optimize away the catch, but that's not reliable
     enough, right? It doesn't play nicely with macrostep, for instance.
     Is there a better way to do this?

   - Documenting the new behavior is a bit weird due to the potential
     interaction with lexical-binding. I have a few paragraphs in the
     docstrings Texinfo manual indicating that cl-return-from may
     behave erratically if there are any non-lexical-binding cl-blocks
     in effect.

     The existing documentation is not quite correct anyway.

More general questions for the list:

   - Is this a worthwhile thing to fix in Emacs? I would say yes, else
     I wouldn't be trying it, but I don't know if other people agree.

     The complexity increase in documentation from interactions with
     non-lexical-binding code is awkward, especially. How much do we
     need to worry about that? Is the general trend for lexical-binding
     to be strongly recommended enough that not giving details of
     what happens if it's off (other than that the correct use cases
     should still work) is okay?

   - If so, do I sound reasonably on the right track above? Would it be
     helpful to present a draft patch?

   - The reason I have not already presented a draft patch is because in
     futures where the code is integrated into Emacs, I would have to
     perform a copyright assignment. I do not object to this, but I also
     do not use my government-recognized name as my social name in this
     context. I am okay with the FSF keeping a record of my government
     name for legal purposes, but I would rather it not be included in
     publications anyplace too obvious. Is this a request that I can
     expect to be honored? What would be the impact of this on the
     assignment procedure? I am a US citizen.

-RTT



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cl-block less lexical than expected
  2022-01-04 19:29   ` Robin Tarsiger
@ 2022-01-04 20:11     ` Eli Zaretskii
  0 siblings, 0 replies; 5+ messages in thread
From: Eli Zaretskii @ 2022-01-04 20:11 UTC (permalink / raw)
  To: Robin Tarsiger; +Cc: emacs-devel

> Date: Tue, 4 Jan 2022 13:29:23 -0600
> From: Robin Tarsiger <rtt@dasyatidae.com>
> 
>    - The reason I have not already presented a draft patch is because in
>      futures where the code is integrated into Emacs, I would have to
>      perform a copyright assignment. I do not object to this, but I also
>      do not use my government-recognized name as my social name in this
>      context. I am okay with the FSF keeping a record of my government
>      name for legal purposes, but I would rather it not be included in
>      publications anyplace too obvious. Is this a request that I can
>      expect to be honored? What would be the impact of this on the
>      assignment procedure? I am a US citizen.

There should be no problems with that, the FSF staff know how to
handle these cases.  Your legal name will not appear in public
records, only the pseudonym you choose.  Just tell the copyright clerk
about this when you email your paperwork, and they will take it from
there.

Thank you for your interest in Emacs.




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-01-04 20:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-30 18:12 cl-block less lexical than expected Robin Tarsiger
2021-12-30 18:15 ` Robin Tarsiger
2021-12-30 18:50 ` Stefan Monnier
2022-01-04 19:29   ` Robin Tarsiger
2022-01-04 20:11     ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).