unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* lexical-binding defined by the caller not the called?
@ 2013-04-28 11:26 Nic Ferrier
  2013-04-28 11:53 ` Pascal J. Bourguignon
  0 siblings, 1 reply; 7+ messages in thread
From: Nic Ferrier @ 2013-04-28 11:26 UTC (permalink / raw)
  To: emacs-devel

Imagine this is a file:

;;; -*- lexical-binding: t -*-

(defun my-cool-fun ()
  lexical-binding)

(ert-deftest my-cool-fun ()
  (should (my-cool-fun)))

(ert 'my-cool-fun)

;;; End


eval-buffer that and it fails. Why does it fail? it appears that
lexical-binding is defined by the caller of a function, not the called
function (and the file defining ert is not lexical-binding: t). 

I thought it was the other way around.

Am I seeing some bug or is this the correct behaviour?


Nic Ferrier



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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 11:26 lexical-binding defined by the caller not the called? Nic Ferrier
@ 2013-04-28 11:53 ` Pascal J. Bourguignon
  2013-04-28 13:59   ` Nic Ferrier
  0 siblings, 1 reply; 7+ messages in thread
From: Pascal J. Bourguignon @ 2013-04-28 11:53 UTC (permalink / raw)
  To: emacs-devel

Nic Ferrier <nferrier@ferrier.me.uk> writes:

> Imagine this is a file:
>
> ;;; -*- lexical-binding: t -*-
>
> (defun my-cool-fun ()
>   lexical-binding)
>
> (ert-deftest my-cool-fun ()
>   (should (my-cool-fun)))
>
> (ert 'my-cool-fun)
>
> ;;; End
>
>
> eval-buffer that and it fails. Why does it fail? it appears that
> lexical-binding is defined by the caller of a function, not the called
> function (and the file defining ert is not lexical-binding: t). 
>
> I thought it was the other way around.
>
> Am I seeing some bug or is this the correct behaviour?

It fails because lexical-binding is a special variable (in CL terms).


---(cool.el)------------------------------------------------------------
;;; -*- lexical-binding: t -*-

(let ((lexical-variable 42))
 (defun my-cool-fun ()
   lexical-variable)) ; this lexical-variable is a lexical variable

;;; End
------------------------------------------------------------------------


---(cool-test.el)-------------------------------------------------------
;;; -*- lexical-binding: nil -*-

(ert-deftest my-cool-fun ()
   (should (let ((lexical-variable 'not!)) ; this lexical-variable is not
              (eql 42 (my-cool-fun)))))    ; a lexical variable!

(ert 'my-cool-fun)

;;; End
------------------------------------------------------------------------


Selector: my-cool-fun
Passed: 1
Failed: 0
Total:  1/1

Started at:   2013-04-28 13:51:49+0200
Finished.
Finished at:  2013-04-28 13:51:49+0200




-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 11:53 ` Pascal J. Bourguignon
@ 2013-04-28 13:59   ` Nic Ferrier
  2013-04-28 14:10     ` Pascal J. Bourguignon
  0 siblings, 1 reply; 7+ messages in thread
From: Nic Ferrier @ 2013-04-28 13:59 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: emacs-devel

"Pascal J. Bourguignon" <pjb@informatimago.com> writes:

> It fails because lexical-binding is a special variable (in CL terms).

Doh.

That is a really good point.

How do I check for lexical-binding then?


Nic



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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 13:59   ` Nic Ferrier
@ 2013-04-28 14:10     ` Pascal J. Bourguignon
  2013-04-28 17:50       ` Nic Ferrier
  0 siblings, 1 reply; 7+ messages in thread
From: Pascal J. Bourguignon @ 2013-04-28 14:10 UTC (permalink / raw)
  To: emacs-devel

Nic Ferrier <nferrier@ferrier.me.uk> writes:

> "Pascal J. Bourguignon" <pjb@informatimago.com> writes:
>
>> It fails because lexical-binding is a special variable (in CL terms).
>
> Doh.
>
> That is a really good point.
>
> How do I check for lexical-binding then?

Read again the code I posted along.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 14:10     ` Pascal J. Bourguignon
@ 2013-04-28 17:50       ` Nic Ferrier
  2013-04-28 19:40         ` Pascal J. Bourguignon
  2013-05-04 20:01         ` Stefan Monnier
  0 siblings, 2 replies; 7+ messages in thread
From: Nic Ferrier @ 2013-04-28 17:50 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: emacs-devel

"Pascal J. Bourguignon" <pjb@informatimago.com> writes:

> Nic Ferrier <nferrier@ferrier.me.uk> writes:

>> How do I check for lexical-binding then?
>
> Read again the code I posted along.

I did. I can't see how that shows me how to test lexical-binding though.

It seems like I can't tell if I'm executing in a lexical-binding
environment or not. 

I want to be able to write a macro that understands when it is, or is
not, executing code inside a lexical-binding environment.



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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 17:50       ` Nic Ferrier
@ 2013-04-28 19:40         ` Pascal J. Bourguignon
  2013-05-04 20:01         ` Stefan Monnier
  1 sibling, 0 replies; 7+ messages in thread
From: Pascal J. Bourguignon @ 2013-04-28 19:40 UTC (permalink / raw)
  To: emacs-devel

Nic Ferrier <nferrier@ferrier.me.uk> writes:

> "Pascal J. Bourguignon" <pjb@informatimago.com> writes:
>
>> Nic Ferrier <nferrier@ferrier.me.uk> writes:
>
>>> How do I check for lexical-binding then?
>>
>> Read again the code I posted along.
>
> I did. I can't see how that shows me how to test lexical-binding though.

You keep saying things that are rather meaningless.

To test the value of the variable named lexical-binding, you just write
lexical-binding in a place in the code where it's evaluated.
For example: 

    (insert (if lexical-binding "lexical" "dynamic"))


To test whether a variable is a lexical variable or a special variable
you can use this macro:

(defmacro lexical-variable-p (symbol)
  `(let ((,symbol t))
     (flet ((f () ,symbol))
       (let ((,symbol nil))
         (f)))))

(eval-when (compile load eval) (setf lexical-binding t))
(let ((toto 42))
  (list (lexical-variable-p toto)
        (lexical-variable-p lexical-binding)))
;; --> (t nil)

(eval-when (compile load eval) (setf lexical-binding nil))
(let ((toto 42))
  (list (lexical-variable-p toto)
        (lexical-variable-p lexical-binding)))
;; --> (nil nil)



Notice that the result is independenant of the setting of
lexical-binding at run-time:

(eval-when (compile load eval) (setf lexical-binding t))
(let ((toto 42))
  (list (lexical-variable-p toto)
        (lexical-variable-p lexical-binding)
        (let ((lexical-binding nil))
          (list  (lexical-variable-p toto)
                 (lexical-variable-p lexical-binding)))))
;; --> (t nil (t nil))

(eval-when (compile load eval) (setf lexical-binding nil))
(let ((toto 42))
  (list (lexical-variable-p toto)
        (lexical-variable-p lexical-binding)
        (let ((lexical-binding t))
          (list  (lexical-variable-p toto)
                 (lexical-variable-p lexical-binding)))))
;; --> (nil nil (nil nil))




> It seems like I can't tell if I'm executing in a lexical-binding
> environment or not. 


The dynamic variable named lexical-binding tells you whether the
_current_, at the _time_ of execution, "environment" is lexical or not.

Of course, this is entirely irrelevant, since at run-time you don't
usually load or compile code.  But if you do, then lexical-binding tells
you whether let will establish lexical variables for new bindings.


> I want to be able to write a macro that understands when it is, or is
> not, executing code inside a lexical-binding environment.

Macros are expanded at compilation time, so again, it's totally
unrelated to whatever happens to lexical-binding at run-time.

You can just test lexical-binding in the macro:


(defmacro m (var init-expr incr-expr)
  (if lexical-binding
    `(let ((,var ,init-expr))
      (lambda () ,incr-expr ,var))
    (let ((unique-var (gensym)))
       `(progn
          (setf (symbol-value ',unique-var)  ,init-expr)
          (lambda () (let ((,var (symbol-value ',unique-var))) 
                        ,incr-expr
                        (setf (symbol-value ',unique-var) ,var)))))))

(eval-when (compile load eval) (setf lexical-binding nil))
(let ((f (m x 0 (incf x))))
  (list (macroexpand '(m x 0 (incf x)))
        (list (funcall f) (let ((x 42)) (funcall f))  (funcall f))))
;; --> ((progn (setf (symbol-value (quote #1=#:G123027)) 0)
;;         (lambda nil (let ((x (symbol-value (quote #1#)))) (incf x) (setf (symbol-value (quote #1#)) x))))
;;      (1 2 3))

(eval-when (compile load eval) (setf lexical-binding t))
(let ((f (m x 0 (incf x))))
  (list (macroexpand '(m x 0 (incf x)))
        (list (funcall f) (let ((x 42)) (funcall f))  (funcall f))))
;; --> ((let ((x 0)) (lambda nil (incf x) x))
;;      (1 2 3))




-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




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

* Re: lexical-binding defined by the caller not the called?
  2013-04-28 17:50       ` Nic Ferrier
  2013-04-28 19:40         ` Pascal J. Bourguignon
@ 2013-05-04 20:01         ` Stefan Monnier
  1 sibling, 0 replies; 7+ messages in thread
From: Stefan Monnier @ 2013-05-04 20:01 UTC (permalink / raw)
  To: Nic Ferrier; +Cc: Pascal J. Bourguignon, emacs-devel

>>> How do I check for lexical-binding then?
>> Read again the code I posted along.
> I did.  I can't see how that shows me how to test lexical-binding though.
> It seems like I can't tell if I'm executing in a lexical-binding
> environment or not.

> I want to be able to write a macro that understands when it is, or is
> not, executing code inside a lexical-binding environment.

It's a good question.  But you need to be careful about what you mean
because the code you showed does not do what you describe (e.g. it
doesn't do any macro expansion).

Testing the value of `lexical-binding' from within a function won't
tell you if that function is itself using lexical binding or not.

But testing `lexical-binding' during macro expansion should tell you
whether the expanded code will be interpreted as lexically scoped
or not.  It's actually not 100% reliable (e.g. lexical-binding is
a buffer-local variable, so if you switch buffer during your macro
expansion, you might bump into some corner cases), but it should work
well in practice (tho less so in 24.1 where there were a few more
problematic cases that I had forgotten).


        Stefan



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

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

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-28 11:26 lexical-binding defined by the caller not the called? Nic Ferrier
2013-04-28 11:53 ` Pascal J. Bourguignon
2013-04-28 13:59   ` Nic Ferrier
2013-04-28 14:10     ` Pascal J. Bourguignon
2013-04-28 17:50       ` Nic Ferrier
2013-04-28 19:40         ` Pascal J. Bourguignon
2013-05-04 20:01         ` Stefan Monnier

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