unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Lambda in macrolet becomes a closure? (another breaking change in emacs:))
@ 2016-09-19 16:43 Constantin Kulikov
  2016-09-19 18:12 ` Stefan Monnier
  2016-09-23 17:19 ` Constantin Kulikov
  0 siblings, 2 replies; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-19 16:43 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 443 bytes --]

in emacs version "25.1.50.2", this:

(macrolet ((tm () (let ((fu #'(lambda () t)))
                           `(list ,fu))))
           (tm))


gives an errror: Symbol’s function definition is void: closure

This:

(macrolet ((tm () (let ((fu #'(lambda () t)))
                           `(list (function ,fu)))))
           (tm))


returns ((closure (t) nil t))

in emacs "24.3.1", both variants returns ((lambda nil t))

[-- Attachment #2: Type: text/html, Size: 953 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-19 16:43 Lambda in macrolet becomes a closure? (another breaking change in emacs:)) Constantin Kulikov
@ 2016-09-19 18:12 ` Stefan Monnier
  2016-09-23 16:01   ` Michael Heerdegen
  2016-09-23 17:19 ` Constantin Kulikov
  1 sibling, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2016-09-19 18:12 UTC (permalink / raw)
  To: emacs-devel

> in emacs version "25.1.50.2", this:
> (macrolet ((tm () (let ((fu #'(lambda () t)))
>                            `(list ,fu))))
>            (tm))

Here, `fu' is a function *value*, rather than a function *expression*
(where I take those words to mean that an /expression/ is what you pass
to `eval` and that returns ` /value/).

In `(list ,fu) you take that value and plug it into the source code,
which in general might not work correctly (although you may often get
lucky since in Elisp, many values are "self-quoting" meaning that they
are also valid expressions which evaluate to themselves).

> gives an errror: Symbol’s function definition is void: closure

Indeed, in a lexical-binding context, a function value will sometimes
look like (closure ...) which is not a valid expression (there is no
function nor macro named `closure').

> (macrolet ((tm () (let ((fu #'(lambda () t)))
>                            `(list (function ,fu)))))
>            (tm))
> returns ((closure (t) nil t))

This will sometimes work as well.  Probably more often than the previous
example.  Yet it's still not correct.  To quote a value, you want to use
`quote` rather than `function`.  `function` can only be used reliably to
quote a "function expression" rather than a function value.  A function
expression is basically either a symbol (the name of a function), or
a sexp of the form (lambda <args> <body>).

> in emacs "24.3.1", both variants returns ((lambda nil t))

Yes, sometimes.


        Stefan




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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-19 18:12 ` Stefan Monnier
@ 2016-09-23 16:01   ` Michael Heerdegen
  2016-09-23 16:13     ` Stefan Monnier
  0 siblings, 1 reply; 14+ messages in thread
From: Michael Heerdegen @ 2016-09-23 16:01 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

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

> [...] To quote a value, you want to use `quote` rather than
> `function`.  `function` can only be used reliably to quote a "function
> expression" rather than a function value.  A function expression is
> basically either a symbol (the name of a function), or a sexp of the
> form (lambda <args> <body>).

Shouldn't the docstring of `function':

| Like `quote', but preferred for objects which are functions [...]

then better speak of (function) expressions instead of `objects'?


Michael.




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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-23 16:01   ` Michael Heerdegen
@ 2016-09-23 16:13     ` Stefan Monnier
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Monnier @ 2016-09-23 16:13 UTC (permalink / raw)
  To: emacs-devel

> Shouldn't the docstring of `function':
> | Like `quote', but preferred for objects which are functions [...]
> then better speak of (function) expressions instead of `objects'?

Oh yes.  This is a relic of the pre-lexical scoping days where
there was no difference between a function expression and its value.


        Stefan




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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-19 16:43 Lambda in macrolet becomes a closure? (another breaking change in emacs:)) Constantin Kulikov
  2016-09-19 18:12 ` Stefan Monnier
@ 2016-09-23 17:19 ` Constantin Kulikov
  2016-09-23 19:03   ` Stefan Monnier
  2016-09-25 18:01   ` Michael Heerdegen
  1 sibling, 2 replies; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-23 17:19 UTC (permalink / raw)
  To: emacs-devel, Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 956 bytes --]

Thanks for the explanation.

However:

> To quote a value, you want to use `quote` rather than `function`.

I tried something different:

(setq lexical-binding t)
(let ((var 1))
        (let* ((fu #'(lambda (a) (+ a var)))
               ba)
          (message "%s" `,fu)
         (setq ba (byte-compile `(lambda (b) (funcall (quote ,fu) b))))
         (funcall ba 2)))


and it seems to work well,  but

(setq lexical-binding nil)
(let* ((fu #'(lambda (a) (+ a 1)))
               ba)
          (message "%s" `,fu)
          (let (byte-compile-warnings)
           (setq ba (byte-compile `(lambda (b) (funcall (quote ,fu) b)))))
         (funcall ba 2))


 results in a *Compile-Log* buffer pop up with

Warning: (lambda (a) ...) quoted with ' rather than with #'


So (if I understend correctly) I can not predict that the value of the `fu'
will be a (closure ...) or a (lambda ...), then how I can decide how to
quote this value or silence the warning?

[-- Attachment #2: Type: text/html, Size: 3823 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-23 17:19 ` Constantin Kulikov
@ 2016-09-23 19:03   ` Stefan Monnier
  2016-09-25 11:06     ` Constantin Kulikov
  2016-09-25 18:01   ` Michael Heerdegen
  1 sibling, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2016-09-23 19:03 UTC (permalink / raw)
  To: Constantin Kulikov; +Cc: emacs-devel

> and it seems to work well,  but
>
> (setq lexical-binding nil)
> (let* ((fu #'(lambda (a) (+ a 1)))
>                ba)
>           (message "%s" `,fu)
>           (let (byte-compile-warnings)
>            (setq ba (byte-compile `(lambda (b) (funcall (quote ,fu) b)))))
>          (funcall ba 2))
>
>  results in a *Compile-Log* buffer pop up with
>
> Warning: (lambda (a) ...) quoted with ' rather than with #'

Notice it says "warning", not "error".

> So (if I understend correctly) I can not predict that the value of the `fu'
> will be a (closure ...) or a (lambda ...),

Or any other object that can be passed to `funcall`, indeed.

> then how I can decide how to quote this value or silence the warning?

If you're worried about the warning, silence it with
`with-no-warnings`, since in this particular case you know that the
(lambda ()...) is a function *value* and not a function expression,
hence the warning is incorrect.

We could *fix* the warning once and for all by changing the
implementation of the `function` special form so that it just always
returns a (closure ...), so that (lambda ...) is only ever used as
a source code expression and never as a function value.  I think it
would be a good change, but I expect lots of people would complain about
such a gratuitous change.


        Stefan



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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-23 19:03   ` Stefan Monnier
@ 2016-09-25 11:06     ` Constantin Kulikov
  2016-09-25 14:15       ` Stefan Monnier
  0 siblings, 1 reply; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-25 11:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 306 bytes --]

> If you're worried about the warning, silence it with `with-no-warnings`
I don't know why but it doesn't work here and *Compile-Log* buffer still
pops up in a view.
Wrapping the code with

(let ((warning-minimum-level :emergency)) ...)

does better -- it logs to the *Compile-Log* silently in background.

[-- Attachment #2: Type: text/html, Size: 648 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-25 11:06     ` Constantin Kulikov
@ 2016-09-25 14:15       ` Stefan Monnier
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Monnier @ 2016-09-25 14:15 UTC (permalink / raw)
  To: Constantin Kulikov; +Cc: emacs-devel

>> If you're worried about the warning, silence it with `with-no-warnings`
> I don't know why but it doesn't work here and *Compile-Log* buffer still
> pops up in a view.

My crystal ball tells me you're putting the with-no-warning around the
wrong code.  Since we're in a macro, there are 2 "times" (compilation
of the macro itself, and compilation of the code generated by the macro
expansion), so you have to be careful to put the with-no-warning such
that it is seen at the right time.


        Stefan



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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-23 17:19 ` Constantin Kulikov
  2016-09-23 19:03   ` Stefan Monnier
@ 2016-09-25 18:01   ` Michael Heerdegen
  2016-09-25 18:53     ` Stefan Monnier
  2016-09-27  9:13     ` Constantin Kulikov
  1 sibling, 2 replies; 14+ messages in thread
From: Michael Heerdegen @ 2016-09-25 18:01 UTC (permalink / raw)
  To: Constantin Kulikov; +Cc: Stefan Monnier, emacs-devel

Constantin Kulikov <zxnotdead@gmail.com> writes:

> [...] then how I can decide how to quote this value [...]?

By looking at the value (or do I miss something)?

#+begin_src emacs-lisp
(let ((var 1))
  (let* ((fu #'(lambda (a) (+ a var)))
         ba)
    (message "%s" `,fu)
    (setq ba (byte-compile `(lambda (b) (funcall ,(if (equal (car-safe fu) 'lambda) `#',fu `',fu) b))))
    (funcall ba 3)))
#+end_src

:-)


Michael.



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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-25 18:01   ` Michael Heerdegen
@ 2016-09-25 18:53     ` Stefan Monnier
  2016-09-27  9:13     ` Constantin Kulikov
  1 sibling, 0 replies; 14+ messages in thread
From: Stefan Monnier @ 2016-09-25 18:53 UTC (permalink / raw)
  To: emacs-devel

>> [...] then how I can decide how to quote this value [...]?
> By looking at the value (or do I miss something)?

> #+begin_src emacs-lisp
> (let ((var 1))
>   (let* ((fu #'(lambda (a) (+ a var)))
>          ba)
>     (message "%s" `,fu)
>     (setq ba (byte-compile `(lambda (b) (funcall ,(if (equal (car-safe fu) 'lambda) `#',fu `',fu) b))))
>     (funcall ba 3)))
> #+end_src

FWIW, in this case, the byte-compiler's warning is incorrect: it tries
to warn the programmer about the all-too common habit of using '(lambda
...) instead of #'(lambda ....) in the source code, but in the present
example, the quoted (lambda ...) is actually indeed a function value we
want to quote as-is rather than a function expression.

So I think it's better to use with-no-warnings (which I generally don't
like to use) than to do as above, which feels like a hack.

Of course, taking a step back, if the whole code gets byte-compiled (as
it should), then the problem doesn't even appear since #'(lambda (a) (+
a var)) will not evaluate to (lambda (a) (+ a var)) but to a bytecoded
function (which needs to be quoted with `quote` rather than with
`function`).


        Stefan




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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-25 18:01   ` Michael Heerdegen
  2016-09-25 18:53     ` Stefan Monnier
@ 2016-09-27  9:13     ` Constantin Kulikov
  2016-09-27  9:19       ` Constantin Kulikov
  1 sibling, 1 reply; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-27  9:13 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 572 bytes --]

> Since we're in a macro
Actualy I run the code at run-time. I need to generate function and
byte-compile it at runtime.
Does `with-no-warnings' intended to be used at compile-time?
I'm running this code in `ielm' and still get a warning

(with-no-warnings
        (let* ((fu #'(lambda (a) (+ a 1)))
               ba)
          (message "%s" `,fu)
          (let (byte-compile-warnings)
           (setq ba (byte-compile `(lambda (b) (funcall (quote ,fu) b)))))
         (funcall ba 2)))


> By looking at the value (or do I miss something)?
Yes, car-safe works, thanks)

[-- Attachment #2: Type: text/html, Size: 1302 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-27  9:13     ` Constantin Kulikov
@ 2016-09-27  9:19       ` Constantin Kulikov
  2016-09-27 11:53         ` Constantin Kulikov
  0 siblings, 1 reply; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-27  9:19 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 320 bytes --]

Heh, just found the place where the `with-no-warnings' seem to work for me:

(let* ((fu #'(lambda (a) (+ a 1)))
               ba)
          (message "%s" `,fu)
          (let (byte-compile-warnings)
            (setq ba (byte-compile `(lambda (b) (funcall (with-no-warnings
(quote ,fu)) b)))))
         (funcall ba 2))

[-- Attachment #2: Type: text/html, Size: 647 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-27  9:19       ` Constantin Kulikov
@ 2016-09-27 11:53         ` Constantin Kulikov
  2016-09-27 14:57           ` Michael Heerdegen
  0 siblings, 1 reply; 14+ messages in thread
From: Constantin Kulikov @ 2016-09-27 11:53 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 863 bytes --]

Also, by looking at `minibuffer-with-setup-hook':

(defmacro minibuffer-with-setup-hook (fun &rest body)
  (declare (indent 1) (debug t))
  (let ((hook (make-symbol "setup-hook"))
        (funsym (make-symbol "fun"))
        (append nil))
    (when (eq (car-safe fun) :append)
      (setq append '(t) fun (cadr fun)))
    `(let ((,funsym ,fun)
           ,hook)
       (setq ,hook
             (lambda ()
               ;; Clear out this hook so it does not interfere
               ;; with any recursive minibuffer usage.
               (remove-hook 'minibuffer-setup-hook ,hook)
               (funcall ,funsym)))
       (unwind-protect
           (progn
             (add-hook 'minibuffer-setup-hook ,hook ,@append)
             ,@body)
         (remove-hook 'minibuffer-setup-hook ,hook)))))


There is no quotation of the fun, funsym or hook. Is it correct?

[-- Attachment #2: Type: text/html, Size: 1347 bytes --]

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

* Re: Lambda in macrolet becomes a closure? (another breaking change in emacs:))
  2016-09-27 11:53         ` Constantin Kulikov
@ 2016-09-27 14:57           ` Michael Heerdegen
  0 siblings, 0 replies; 14+ messages in thread
From: Michael Heerdegen @ 2016-09-27 14:57 UTC (permalink / raw)
  To: Constantin Kulikov; +Cc: Stefan Monnier, emacs-devel

Constantin Kulikov <zxnotdead@gmail.com> writes:

> Also, by looking at `minibuffer-with-setup-hook' [...]  There is no
> quotation of the fun, funsym or hook. Is it correct?

A good question.  But I think the definition is correct in this regard.

FUN is (bound to) an expression (since `minibuffer-with-setup-hook' is a
macro and FUN is just "pasted" into the expansion without evaluation).

If you look at the expansion (let's use a lambda form as FUN):

#+begin_src emacs-lisp
(macroexpand-1
 '(minibuffer-with-setup-hook
      (lambda () (do-some-setup))  do-this do-that))
==>
(let
    ((#2=#:fun
      (lambda nil
        (do-some-setup)))
     #1=#:setup-hook)
  (setq #1#
        (lambda nil
          (remove-hook #3='minibuffer-setup-hook #1#)
          (funcall #2#)))
  (unwind-protect
      (progn
        (add-hook #3# #1#)
        do-this do-that)
    (remove-hook #3# #1#)))
#+end_src

you see that nowhere a function value is evaluated.  In some cases, a
function expression is bound to a symbol (`let', `setq'), in the other
cases, the code refers to the binding of these symbols.


Michael.



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

end of thread, other threads:[~2016-09-27 14:57 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-19 16:43 Lambda in macrolet becomes a closure? (another breaking change in emacs:)) Constantin Kulikov
2016-09-19 18:12 ` Stefan Monnier
2016-09-23 16:01   ` Michael Heerdegen
2016-09-23 16:13     ` Stefan Monnier
2016-09-23 17:19 ` Constantin Kulikov
2016-09-23 19:03   ` Stefan Monnier
2016-09-25 11:06     ` Constantin Kulikov
2016-09-25 14:15       ` Stefan Monnier
2016-09-25 18:01   ` Michael Heerdegen
2016-09-25 18:53     ` Stefan Monnier
2016-09-27  9:13     ` Constantin Kulikov
2016-09-27  9:19       ` Constantin Kulikov
2016-09-27 11:53         ` Constantin Kulikov
2016-09-27 14:57           ` Michael Heerdegen

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).