From: ·············@gmail.com
Subject: eql and closures
Date: 
Message-ID: <1146608328.387303.136350@i39g2000cwa.googlegroups.com>
Hi all,

Consider the following session:

CL-USER> (defun fun ()
	     (let* ((i 3)
		    (cl1 #'(lambda () (incf i)))
		    (cl2 cl1))
	       (print cl1)
	       (print cl2)
	       (eql (print cl1) (print cl2))))
FUN
CL-USER> (fun)

#<Interpreted Function "LAMBDA NIL" {5883E5B1}>
#<Interpreted Function "LAMBDA NIL" {5883E5B1}>
#<Interpreted Function "LAMBDA NIL" {5883E5B1}>
#<Interpreted Function "LAMBDA NIL" {5883E5B1}>
T
CL-USER> (compile 'fun)
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:
FUN
NIL
NIL
CL-USER> (fun)

#<Closure Over Function "LAMBDA NIL" {58863391}>
#<Closure Over Function "LAMBDA NIL" {58863679}>
#<Closure Over Function "LAMBDA NIL" {58863961}>
#<Closure Over Function "LAMBDA NIL" {58863C49}>
NIL
CL-USER>

As you can see, in the compiled version of fun, cl1 and cl2 are
different everytime I print them. They also don't compare to T with
eql.

I was surprised to notice this. Is there anyone with an explanation for
this?

Are there any other situations where the following is not garantueed to
be T:
(let ((a some-other-thing)) (eql a some-other-thing))

Thanks a lot,

Kris

From: ·············@gmail.com
Subject: Re: eql and closures
Date: 
Message-ID: <1146608576.215341.238320@y43g2000cwc.googlegroups.com>
I forgot to tell which implementation I am using: cmucl 19a.

Is the above a cmucl only 'feature'? What does the standard say about
this?

·············@gmail.com wrote:
> Hi all,
>
> Consider the following session:
>
> CL-USER> (defun fun ()
> 	     (let* ((i 3)
> 		    (cl1 #'(lambda () (incf i)))
> 		    (cl2 cl1))
> 	       (print cl1)
> 	       (print cl2)
> 	       (eql (print cl1) (print cl2))))
> FUN
> CL-USER> (fun)
>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> T
> CL-USER> (compile 'fun)
> ; Compiling LAMBDA NIL:
> ; Compiling Top-Level Form:
> FUN
> NIL
> NIL
> CL-USER> (fun)
>
> #<Closure Over Function "LAMBDA NIL" {58863391}>
> #<Closure Over Function "LAMBDA NIL" {58863679}>
> #<Closure Over Function "LAMBDA NIL" {58863961}>
> #<Closure Over Function "LAMBDA NIL" {58863C49}>
> NIL
> CL-USER>
>
> As you can see, in the compiled version of fun, cl1 and cl2 are
> different everytime I print them. They also don't compare to T with
> eql.
>
> I was surprised to notice this. Is there anyone with an explanation for
> this?
>
> Are there any other situations where the following is not garantueed to
> be T:
> (let ((a some-other-thing)) (eql a some-other-thing))
> 
> Thanks a lot,
> 
> Kris
From: Carl Shapiro
Subject: Re: eql and closures
Date: 
Message-ID: <ouyaca0ja69.fsf@panix3.panix.com>
··············@gmail.com" <·············@gmail.com> writes:

> I forgot to tell which implementation I am using: cmucl 19a.
>
> Is the above a cmucl only 'feature'? What does the standard say about
> this?

While the outermost closure objects are not EQ the closed over lexical
environments of c1 and c2 are in fact EQ which allows for the expected
behavior.  The underlying code vector should be shared as well.

(defvar *c1* nil)
(defvar *c2* nil)
(defun fun ()
  (let* ((i 3)
         (cl1 #'(lambda () (incf i)))
         (cl2 cl1))
    (setq *c1* (print cl1))
    (setq *c2* (print cl2))
    (eql (print cl1) (print cl2))))

FUN
* (compile *)
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 

FUN
NIL
NIL
* (fun)

#<Closure Over Function "LAMBDA NIL" {400AA8F9}> 
#<Closure Over Function "LAMBDA NIL" {400AAC39}> 
#<Closure Over Function "LAMBDA NIL" {400AAF79}> 
#<Closure Over Function "LAMBDA NIL" {400AB2B9}> 
NIL
* (describe '*c2*)

*C2* is an internal symbol in the COMMON-LISP-USER package.
It is a special variable; its value is #<Closure Over Function "LAMBDA
NIL"
                                         {400AAC39}>.
   #<Closure Over Function "LAMBDA NIL" {400AAC39}> is function.
   Arguments:
     There are no arguments.
   Its defined argument types are:
     NIL
   Its result type is:
     NUMBER
   On Tuesday, 5/2/06 04:03:03 pm PDT it was compiled from:
   #(#'(LAMBDA # #))
   Its closure environment is:
   0: #<Value Cell 3 {400AA8F7}>
* (describe '*c1*)

*C1* is an internal symbol in the COMMON-LISP-USER package.
It is a special variable; its value is #<Closure Over Function "LAMBDA
NIL"
                                         {400AA8F9}>.
   #<Closure Over Function "LAMBDA NIL" {400AA8F9}> is function.
   Arguments:
     There are no arguments.
   Its defined argument types are:
     NIL
   Its result type is:
     NUMBER
   On Tuesday, 5/2/06 04:03:03 pm PDT it was compiled from:
   #(#'(LAMBDA # #))
   Its closure environment is:
   0: #<Value Cell 3 {400AA8F7}>
* 
From: Ari Johnson
Subject: Re: eql and closures
Date: 
Message-ID: <m2k6942hh2.fsf@hermes.theari.com>
··············@gmail.com" <·············@gmail.com> writes:

> Hi all,
>
> Consider the following session:
>
> CL-USER> (defun fun ()
> 	     (let* ((i 3)
> 		    (cl1 #'(lambda () (incf i)))
> 		    (cl2 cl1))
> 	       (print cl1)
> 	       (print cl2)
> 	       (eql (print cl1) (print cl2))))
> FUN
> CL-USER> (fun)
>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> #<Interpreted Function "LAMBDA NIL" {5883E5B1}>
> T
> CL-USER> (compile 'fun)
> ; Compiling LAMBDA NIL:
> ; Compiling Top-Level Form:
> FUN
> NIL
> NIL
> CL-USER> (fun)
>
> #<Closure Over Function "LAMBDA NIL" {58863391}>
> #<Closure Over Function "LAMBDA NIL" {58863679}>
> #<Closure Over Function "LAMBDA NIL" {58863961}>
> #<Closure Over Function "LAMBDA NIL" {58863C49}>
> NIL
> CL-USER>
>
> As you can see, in the compiled version of fun, cl1 and cl2 are
> different everytime I print them. They also don't compare to T with
> eql.
>
> I was surprised to notice this. Is there anyone with an explanation for
> this?
>
> Are there any other situations where the following is not garantueed to
> be T:
> (let ((a some-other-thing)) (eql a some-other-thing))

It's worth nothing that you haven't actually done
  (let ((a some-other-thing)) (eql a some-other-thing))
but rather
  (let ((a some-other-thing)) (eql (print a) (print some-other-thing)))

Not that it makes a real difference.  For what it's worth, OpenMCL
gives me the two things being eql.
From: Alexey Dejneka
Subject: Re: eql and closures
Date: 
Message-ID: <878xpjbzac.fsf@tochka.ru>
··············@gmail.com" <·············@gmail.com> writes:

> CL-USER> (defun fun ()
> 	     (let* ((i 3)
> 		    (cl1 #'(lambda () (incf i)))
> 		    (cl2 cl1))
> 	       (print cl1)
> 	       (print cl2)
> 	       (eql (print cl1) (print cl2))))
[...]
> As you can see, in the compiled version of fun, cl1 and cl2 are
> different everytime I print them. They also don't compare to T with
> eql.

It is a feature of CMUCL. It considers functions to be constants, and
so propagate them freely, but after that it creates closures at every
reference and so may not preserve identity. This is one of the reasons
why DYNAMIC-EXTENT may not work well in CMUCL.

-- 
Regards,
Alexey Dejneka

"Alas, the spheres of truth are less transparent than those of
illusion." -- L.E.J. Brouwer