From: Hannah Schroeter
Subject: Re: [Q] Dylan to Java/JVM compiler?
Date: 
Message-ID: <9dbg6k$fkc$1@c3po.schlund.de>
Hello!

In article <··············@localhost.localdomain>,
Lieven Marchand  <···@wyrd.be> wrote:
>[... evolved from a discussion of declaring methods on make in Dylan,
>     specialized on single classes ...]


>BTW, why does LispWorks complain about the equivalent CL code? The
>Hyperspec specifically allows users to augment the MAKE-INSTANCE
>generic function.

>CL-USER 8 > (defmethod make-instance ((class (eql (find-class
>'abstract))) &rest args)
>              (apply #'make-instance 'concrete args))

>Error: Defining method #<STANDARD-METHOD MAKE-INSTANCE NIL ((EQL
>#<STANDARD-CLASS ABSTRACT 21151714>)) 204D8444> visible from packages
>COMMON-LISP.
>  1 (continue) Define it anyway.
>  2 Discard the new method.
>  3 (abort) Return to level 0.
>  4 Return to top loop level 0.

>It works as expected when you choose restart 1.

Dunno. sbcl accepts the equivalent of that:

(defclass a () ())
(defclass b () ())

(defmethod make-instance ((class (eql (find-class 'a))) &key &allow-other-keys
                          &rest args)
  (apply #'make-instance 'b args))

(It spits out many optimization warnings though)

Now,

(let ((x (make-instance 'a)))
  (class-of x))

yields
#<STANDARD-CLASS A>

while

(let ((x (make-instance (find-class 'a))))
  (class-of x))

yields
#<STANDARD-CLASS B>

So to achieve what was intended, you'd also have to specify
(defmethod make-instance ((class (eql 'a)) ...)
  ...)

Looks like an application for a small macro: define a generic
where one argument position is specialized eql a symbol *and*
the corresponding class.

Kind regards,

Hannah.

From: Lieven Marchand
Subject: Re: [Q] Dylan to Java/JVM compiler?
Date: 
Message-ID: <m34ruue9js.fsf@localhost.localdomain>
······@schlund.de (Hannah Schroeter) writes:

> Hello!
> 
> In article <··············@localhost.localdomain>,
> Lieven Marchand  <···@wyrd.be> wrote:
> >[... evolved from a discussion of declaring methods on make in Dylan,
> >     specialized on single classes ...]
> 
> 
> >BTW, why does LispWorks complain about the equivalent CL code? The
> >Hyperspec specifically allows users to augment the MAKE-INSTANCE
> >generic function.
> 
> >CL-USER 8 > (defmethod make-instance ((class (eql (find-class
> >'abstract))) &rest args)
> >              (apply #'make-instance 'concrete args))
> 
> >Error: Defining method #<STANDARD-METHOD MAKE-INSTANCE NIL ((EQL
> >#<STANDARD-CLASS ABSTRACT 21151714>)) 204D8444> visible from packages
> >COMMON-LISP.
> >  1 (continue) Define it anyway.
> >  2 Discard the new method.
> >  3 (abort) Return to level 0.
> >  4 Return to top loop level 0.
> 
> >It works as expected when you choose restart 1.
> 
> Dunno. sbcl accepts the equivalent of that:
> 
> (defclass a () ())
> (defclass b () ())
> 
> (defmethod make-instance ((class (eql (find-class 'a))) &key &allow-other-keys
>                           &rest args)
>   (apply #'make-instance 'b args))
> 
> (It spits out many optimization warnings though)
> 
> Now,
> 
> (let ((x (make-instance 'a)))
>   (class-of x))
> 
> yields
> #<STANDARD-CLASS A>
> 
> while
> 
> (let ((x (make-instance (find-class 'a))))
>   (class-of x))
> 
> yields
> #<STANDARD-CLASS B>
> 
> So to achieve what was intended, you'd also have to specify
> (defmethod make-instance ((class (eql 'a)) ...)
>   ...)
> 
> Looks like an application for a small macro: define a generic
> where one argument position is specialized eql a symbol *and*
> the corresponding class.
> 

I'm afraid you've found a bug in sbcl ;-)

Section 7.1.7 of the CLHS states


The generic function make-instance behaves as if it were defined as
follows, except that certain optimizations are permitted:

....

 (defmethod make-instance ((class-name symbol) &rest initargs)
   (apply #'make-instance (find-class class-name) initargs))

I don't think the wriggling room the clause about "certain
optimizations" leaves is big enough to cover the behaviour of sbcl.

Once you tell Lispworks to go ahead, (make-instance 'a) returns an
instance of class b. Allegro has the same behaviour but without the
error Lispworks gives.

-- 
Lieven Marchand <···@wyrd.be>
Gla�r ok reifr skyli gumna hverr, unz sinn b��r bana.
From: Hannah Schroeter
Subject: Re: [Q] Dylan to Java/JVM compiler?
Date: 
Message-ID: <9drk08$4vc$1@c3po.schlund.de>
[posted to comp.lang.lisp and mailed to
 sbcl-devel at lists dot sourceforge ... because of bug analysis]

Hello!

In article <··············@localhost.localdomain>,
Lieven Marchand  <···@wyrd.be> wrote:
>······@schlund.de (Hannah Schroeter) writes:

>[...]

>> (defclass a () ())
>> (defclass b () ())

>> (defmethod make-instance ((class (eql (find-class 'a))) &key &allow-other-keys
>>                           &rest args)
>>   (apply #'make-instance 'b args))

>[...]

>> (let ((x (make-instance 'a)))
>>   (class-of x))

>> yields
>> #<STANDARD-CLASS A>

>> while

>> (let ((x (make-instance (find-class 'a))))
>>   (class-of x))

>> yields
>> #<STANDARD-CLASS B>

>[...]

>I'm afraid you've found a bug in sbcl ;-)

>Section 7.1.7 of the CLHS states

>[...]

Looks so.

In sbcl, make-instance has these methods by default:

1. #<FUNCTION "DEFMETHOD MAKE-INSTANCE (COMMON-LISP:CLASS)"
  {1060ABC9}> is a function.

2. #<FUNCTION "DEFMETHOD MAKE-INSTANCE (SYMBOL)" {106022D1}> is a function.

3. #<FUNCTION "DEFMETHOD MAKE-INSTANCE (CLASS)" {106023D1}> is a function.

1. and 3. seem to be distinct. Now, 2. is implemented like this:

(in-package "SB-PCL")
...
(defmethod make-instance ((class symbol) &rest initargs)
  (apply #'make-instance (find-class class) initargs))

Now, there are different cl:find-class and sb-pcl:find-class. The
method for symbol seems to use #'sb-pcl:find-class, which seems to
return a sb-pcl:class; while the (cl:)find-class in

(defmethod make-instance ((class (find-class 'a)) &rest initargs)
  (apply #'make-instance (find-class 'b) initargs))

seems to return a cl:class.

So after that defmethod,

(make-instance 'a) => (make-instance #<SB-PCL:CLASS A>) =>
create an instance of A

while

(make-instance (find-class 'a)) => (make-instance #<CL:CLASS A>) =>
(match the eql specialized method) (make-instance (find-class 'b)) =>
creates an instance of B.

Kind regards,

Hannah.
From: Pekka P. Pirinen
Subject: Re: [Q] Dylan to Java/JVM compiler?
Date: 
Message-ID: <ixd79h2rn8.fsf@harlequin.co.uk>
In article <··············@localhost.localdomain>, (evolved from a
discussion in comp.lang.dylan) Lieven Marchand <···@wyrd.be> wrote:
>BTW, why does LispWorks complain about the equivalent CL code? The
>Hyperspec specifically allows users to augment the MAKE-INSTANCE
>generic function.
>
>CL-USER 8 > (defmethod make-instance ((class (eql (find-class
>'abstract))) &rest args)
>              (apply #'make-instance 'concrete args))
>
>Error: Defining method #<STANDARD-METHOD MAKE-INSTANCE NIL ((EQL
>#<STANDARD-CLASS ABSTRACT 21151714>)) 204D8444> visible from packages
>COMMON-LISP.

That DEFMETHOD is definitely disallowed by item 19 of ANSI 11.1.2.1.2,
since the argument is an instance of a standardized class
(STANDARD-CLASS).

It's not clear whether the specific permission you refer to (ANSI
7.1.7: "Customizing at the Programmer Interface level includes [...]
defining methods for MAKE-INSTANCE,...") is intended to modify that,
or just to point out that you could define methods on (instances of)
your own metaclasses.  Probably the former, but it should have been
more specific, since it was probably not the intention to allow
wholesale redefinition of (METHOD MAKE-INSTANCE (STANDARD-CLASS)).
-- 
Pekka P. Pirinen
"Usenet is essentially Letters to the Editor without the editor.
Editors don't appreciate this, for some reason."  -- Larry Wall
From: Lieven Marchand
Subject: Re: [Q] Dylan to Java/JVM compiler?
Date: 
Message-ID: <m3ae4ltaax.fsf@localhost.localdomain>
·····@harlequin.co.uk (Pekka P. Pirinen) writes:

> In article <··············@localhost.localdomain>, (evolved from a
> discussion in comp.lang.dylan) Lieven Marchand <···@wyrd.be> wrote:
> >BTW, why does LispWorks complain about the equivalent CL code? The
> >Hyperspec specifically allows users to augment the MAKE-INSTANCE
> >generic function.
> >
> >CL-USER 8 > (defmethod make-instance ((class (eql (find-class
> >'abstract))) &rest args)
> >              (apply #'make-instance 'concrete args))
> >
> >Error: Defining method #<STANDARD-METHOD MAKE-INSTANCE NIL ((EQL
> >#<STANDARD-CLASS ABSTRACT 21151714>)) 204D8444> visible from packages
> >COMMON-LISP.
> 
> That DEFMETHOD is definitely disallowed by item 19 of ANSI 11.1.2.1.2,
> since the argument is an instance of a standardized class
> (STANDARD-CLASS).
> 

That section starts with "Except where explicitly allowed" so it's not
very conclusive in this case.

> It's not clear whether the specific permission you refer to (ANSI
> 7.1.7: "Customizing at the Programmer Interface level includes [...]
> defining methods for MAKE-INSTANCE,...") is intended to modify that,
> or just to point out that you could define methods on (instances of)
> your own metaclasses.  Probably the former, but it should have been
> more specific, since it was probably not the intention to allow
> wholesale redefinition of (METHOD MAKE-INSTANCE (STANDARD-CLASS)).

There are a lot of hints in section 7.1 but nothing conclusive. 

7.1 In addition, make-instance is itself a generic function and thus
also can be customized.

One view could be that you're allowed to define :AFTER or :BEFORE
methods but have to let the system supplied method run.

On the other hand, there are sensible uses of redefining MAKE-INSTANCE
for a certain class. Things like implementing the Factory or the
Singleton pattern.

The interpretation of ANSI CL in this case is definitely something
reasonable people can disagree about.

-- 
Lieven Marchand <···@wyrd.be>
Gla�r ok reifr skyli gumna hverr, unz sinn b��r bana.