From: adeht
Subject: Defining an object and a method that specializes on it at the same time
Date: 
Message-ID: <4395b21e$1@news.bezeqint.net>
Hi,

In the following contrived code, I have a macro that returns code whose
purpose is to both define an object, and to create a method specialized
on that object. It works, but not without warnings. I can see why I get
warnings: defmethod evaluates the eql specialization at macro expansion
time, but the name gets bound to the object at load time (I think?). So
at defmethod expansion the implementation treats it as a special name
(Is this standard behaviour?).

I could separate the macro in two (i.e., have a declare-something that
will return the defparameter part), or have a declare-something that
declares a special symbol (at least I think that will work). But my
question is: Is there a better solution, that will keep with the
current domain-specific language (no declare-something) ?

;;;;

(defclass something () ())

(defgeneric foo (obj))

(defmacro define-something (name &body body)
   `(progn
     (defparameter ,name (make-instance 'something))
     (defmethod foo ((obj (eql ,name)))
       ,@body)))

(define-something aaa
   (format t "aaa~%"))

(define-something bbb
   (format t "bbb~%"))

From: Coby Beck
Subject: Re: Defining an object and a method that specializes on it at the same time
Date: 
Message-ID: <Ryjlf.137470$y_1.88663@edtnps89>
"adeht" <·····@hotmail.com> wrote in message 
···············@news.bezeqint.net...
> Hi,
>
> In the following contrived code, I have a macro that returns code whose
> purpose is to both define an object, and to create a method specialized
> on that object. It works, but not without warnings. I can see why I get
> warnings: defmethod evaluates the eql specialization at macro expansion
> time, but the name gets bound to the object at load time (I think?). So
> at defmethod expansion the implementation treats it as a special name
> (Is this standard ehaviour?).

I don't get any warning in LW either at the REPL or putting it into a file 
and compiling and loading.  Nor is it clear to me why you should get one, 
what you say aout the defmethod evaluating at macro expansion time shouldn't 
be the case, the form is returned by the expansion and not evaluated until 
later and after the defparameter form.

> I could separate the macro in two (i.e., have a declare-something that
> will return the defparameter part), or have a declare-something that
> declares a special symbol (at least I think that will work). But my
> question is: Is there a better solution, that will keep with the
> current domain-specific language (no declare-something) ?

As I said, I don't think you should have any problem with it the way you 
have it, but: you could have the macroexpansion actually execute the 
defparameter form instead of returning it to ensure it happens before
the defmethod.


-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")


> (defclass something () ())
>
> (defgeneric foo (obj))
>
> (defmacro define-something (name &body body)
>   `(progn
>     (defparameter ,name (make-instance 'something))
>     (defmethod foo ((obj (eql ,name)))
>       ,@body)))
>
> (define-something aaa
>   (format t "aaa~%"))
>
> (define-something bbb
>   (format t "bbb~%")) 
From: Pascal Costanza
Subject: Re: Defining an object and a method that specializes on it at the same time
Date: 
Message-ID: <3vm1m9F16mu88U2@individual.net>
Coby Beck wrote:
> "adeht" <·····@hotmail.com> wrote in message 
> ···············@news.bezeqint.net...
> 
>>Hi,
>>
>>In the following contrived code, I have a macro that returns code whose
>>purpose is to both define an object, and to create a method specialized
>>on that object. It works, but not without warnings. I can see why I get
>>warnings: defmethod evaluates the eql specialization at macro expansion
>>time, but the name gets bound to the object at load time (I think?). So
>>at defmethod expansion the implementation treats it as a special name
>>(Is this standard ehaviour?).
> 
> I don't get any warning in LW either at the REPL or putting it into a file 
> and compiling and loading.  Nor is it clear to me why you should get one, 
> what you say aout the defmethod evaluating at macro expansion time shouldn't 
> be the case, the form is returned by the expansion and not evaluated until 
> later and after the defparameter form.

You're right and I haven't taken that into account in my reply.

To the OP: What warning do you actually get?


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: adeht
Subject: Re: Defining an object and a method that specializes on it at thesame time
Date: 
Message-ID: <4395d0b3@news.bezeqint.net>
Pascal Costanza wrote:
> 
> You're right and I haven't taken that into account in my reply.
> 
> To the OP: What warning do you actually get?
> 

I don't have SBCL here, but with CLISP, if I try to compile a 
define-something (using emacs/slime, C-c C-c) I get:

WARNING :
AAA is neither declared nor bound,
it will be treated as if it were declared SPECIAL.

Maybe it's an interpreter mode vs. compiler mode thing?
From: Pascal Costanza
Subject: Re: Defining an object and a method that specializes on it at thesame   time
Date: 
Message-ID: <3vmgv8F16sc3nU1@individual.net>
adeht wrote:
> Pascal Costanza wrote:
> 
>> You're right and I haven't taken that into account in my reply.
>>
>> To the OP: What warning do you actually get?
> 
> I don't have SBCL here, but with CLISP, if I try to compile a 
> define-something (using emacs/slime, C-c C-c) I get:
> 
> WARNING :
> AAA is neither declared nor bound,
> it will be treated as if it were declared SPECIAL.
> 
> Maybe it's an interpreter mode vs. compiler mode thing?

No, probably not. I also cannot reproduce the warning, neither in clisp 
nor in SBCL.

Are the forms actually processed in the order in which you have given 
them in your original posting? Maybe the define-something forms are 
processed before the define-something macro? (Then such a warning could 
occur.)

Are you using current versions of clisp and/or SBCL?


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: adeht
Subject: Re: Defining an object and a method that specializes on it at thesametime
Date: 
Message-ID: <439610c0$1@news.bezeqint.net>
Pascal Costanza wrote:
> 
> No, probably not. I also cannot reproduce the warning, neither in clisp 
> nor in SBCL.

Launch emacs/slime. Open test.lisp and type the program in the original 
post. Use C-c C-c to compile each toplevel form. With clisp, two 
warnings should result - one for AAA and one for BBB.

> 
> Are the forms actually processed in the order in which you have given 
> them in your original posting?
> 

Yes.

> Are you using current versions of clisp and/or SBCL?
> 

Yes, latest.
From: jayessay
Subject: Re: Defining an object and a method that specializes on it at thesametime
Date: 
Message-ID: <m34q5lkb4i.fsf@rigel.goldenthreadtech.com>
adeht <·····@hotmail.com> writes:

> Pascal Costanza wrote:
> > No, probably not. I also cannot reproduce the warning, neither in
> > clisp nor in SBCL.
> 
> Launch emacs/slime. Open test.lisp and type the program in the
> original post. Use C-c C-c to compile each toplevel form. With clisp,
> two warnings should result - one for AAA and one for BBB.

I bet you won't see these warnings if you simply (compile-file
"test.cl") at the REPL.  Try it.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: adeht
Subject: Re: Defining an object and a method that specializes on it at thesametime
Date: 
Message-ID: <43962974$1@news.bezeqint.net>
jayessay wrote:
> 
> I bet you won't see these warnings if you simply (compile-file
> "test.cl") at the REPL.  Try it.
> 

Right, but what is the meaning of them with the C-c C-c?

In SBCL, by the way, I recall two types of warnings that appear: ones 
similar to the CLISP ones for C-c C-c, and performance ones (about 
generic eql).

I'm still looking for an explanation about how this works. I suppose I 
should take a mental dive to the HyperSpec for that, but would be nice 
if someone could explain the behaviour(s) in this particular case.
From: jayessay
Subject: Re: Defining an object and a method that specializes on it at thesametime
Date: 
Message-ID: <m3vey1iun7.fsf@rigel.goldenthreadtech.com>
adeht <·····@hotmail.com> writes:

> jayessay wrote:
> > I bet you won't see these warnings if you simply (compile-file
> > "test.cl") at the REPL.  Try it.
> >
> 
> Right, but what is the meaning of them with the C-c C-c?

I would say this is an interaction issue of Emacs/Slime with the Lisp
it is talking to.  There is nothing wrong with your Lisp here.


> I'm still looking for an explanation about how this works. I suppose I
> should take a mental dive to the HyperSpec for that, but would be nice
> if someone could explain the behaviour(s) in this particular case.

I'm pretty sure that what's going on revolves around the DEFPARAMTERs
you have in your code.  Try macroexpanding a DEFPARAMETER (any will
do) and I will bet again that it will have a (declaim (special
<the-name-you-gave>)) in the expansion code.  Next, have a look at
this:

http://www.lispworks.com/documentation/HyperSpec/Body/m_declai.htm

and note the bit about how 1) it is _not_ evaluated and 2) how it
behaves at compile time in top level forms during a compile-file.

Then, note that compiling these individually via C-c C-c from Emacs
does not make use of compile-file.

Finally, note that somewhere in your expansion following the (declaim
...) noted above is a (setf <the-name-you-gave> <the-value-you-gave>)
(or something very close to this).

Then do the following: create a version of this last (setf ...) form
and use C-c C-c on it.  You will see the same warnings...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Pascal Costanza
Subject: Re: Defining an object and a method that specializes on it at thesametime
Date: 
Message-ID: <3vmrl2F15mejpU1@individual.net>
adeht wrote:
> Pascal Costanza wrote:
> 
>>
>> No, probably not. I also cannot reproduce the warning, neither in 
>> clisp nor in SBCL.
> 
> Launch emacs/slime. Open test.lisp and type the program in the original 
> post. Use C-c C-c to compile each toplevel form. With clisp, two 
> warnings should result - one for AAA and one for BBB.

Yes, I can reproduce this.

Here is an idea:

In order to compile single forms and then execute, SLIME maybe uses the 
following trick. Assume it wants to compile (defun foo (x) (+ x x)). It 
cannot just send that s-expression to the underlying CL implementation 
because it is then not guaranteed to be compiled. So in order to 
guarantee compilation, it has to use compile. So it probably creates the 
following form:

(funcall (compile nil (lambda () (defun foo (x) (+ x x)))))

I have tried to compile each toplevel form of your original code step by 
step using that approach manually, and indeed it produces the error you 
mention.

The problem is that the ANSI CL specifies that the fact that a variable 
is defined globally is only ensured to be known in the compile-time 
environment when the corresponding defvar/defparameter form is a 
toplevel form. However, due to the (funcall (compile nil (lambda () 
...))) trick, it is not toplevel anymore.

This is just an assumption, so please anyone versed in SLIME should 
confirm this. But this seems to be likely. You could check by evaluating 
the toplevel forms instead of compiling them in SLIME.

I don't know whether there is a way out if that is really the case.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: adeht
Subject: Re: Defining an object and a method that specializes on it at the same time
Date: 
Message-ID: <4395cf77$1@news.bezeqint.net>
Coby Beck wrote:
> 
> I don't get any warning in LW either at the REPL or putting it into a file 
> and compiling and loading.  Nor is it clear to me why you should get one, 
> what you say aout the defmethod evaluating at macro expansion time shouldn't 
> be the case, the form is returned by the expansion and not evaluated until 
> later and after the defparameter form.
> 

I tried with CLISP and SBCL and both give warnings. To my understanding, 
the define-something macro gets expanded, then the defmethod gets 
expanded, and then it goes on to actually evaluate the progn form. My 
understanding here is pretty limited, however, so I'll be glad if 
someone could clarify.

> 
> As I said, I don't think you should have any problem with it the way you 
> have it, but: you could have the macroexpansion actually execute the 
> defparameter form instead of returning it to ensure it happens before
> the defmethod.
> 

I'm afraid of macros with side-effects, so I'd rather have it split. But 
see Pascal Costanza's reply, which seems to work well.
From: Pascal Costanza
Subject: Re: Defining an object and a method that specializes on it at the   same time
Date: 
Message-ID: <3vm6dtF16tup9U1@individual.net>
adeht wrote:
> Coby Beck wrote:
> 
>>
>> I don't get any warning in LW either at the REPL or putting it into a 
>> file and compiling and loading.  Nor is it clear to me why you should 
>> get one, what you say aout the defmethod evaluating at macro expansion 
>> time shouldn't be the case, the form is returned by the expansion and 
>> not evaluated until later and after the defparameter form.
> 
> I tried with CLISP and SBCL and both give warnings. To my understanding, 
> the define-something macro gets expanded, then the defmethod gets 
> expanded, and then it goes on to actually evaluate the progn form. My 
> understanding here is pretty limited, however, so I'll be glad if 
> someone could clarify.

It's important to tell us what warning you get. It could be that it's 
just a simple "Variable OBJ not used." warning, which would relate to 
something completely different...

Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: Defining an object and a method that specializes on it at the same   time
Date: 
Message-ID: <3vlrobF15jf6mU1@individual.net>
adeht wrote:
> Hi,
> 
> In the following contrived code, I have a macro that returns code whose
> purpose is to both define an object, and to create a method specialized
> on that object. It works, but not without warnings. I can see why I get
> warnings: defmethod evaluates the eql specialization at macro expansion
> time, but the name gets bound to the object at load time (I think?). So
> at defmethod expansion the implementation treats it as a special name
> (Is this standard behaviour?).
> 
> I could separate the macro in two (i.e., have a declare-something that
> will return the defparameter part), or have a declare-something that
> declares a special symbol (at least I think that will work). But my
> question is: Is there a better solution, that will keep with the
> current domain-specific language (no declare-something) ?

You could go through the metaobject protocol, but in this simple case I 
would simply use eval to do this:

> ;;;;
> 
> (defclass something () ())
> 
> (defgeneric foo (obj))
> 
> (defmacro define-something (name &body body)
>   `(progn
>     (defparameter ,name (make-instance 'something))
>     (defmethod foo ((obj (eql ,name)))
>       ,@body)))

(defmacro define-something (name &body body)
   `(progn
      (defparameter ,name (make-instance 'something))
      (eval `(defmethod foo ((object (eql ,',name)))
               ,@,body))))

This is untested, and I am not sure about whether the unquoting is 
correct, but you get the idea.

You could also turn this into a function:

(defun make-something (function)
   (let ((object (make-instance 'something)))
     (eval `(defmethod ((object (eql ,object)) &rest args)
              (apply ,function args)))))

Maybe this is more useful because it's more general.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: adeht
Subject: Re: Defining an object and a method that specializes on it at thesame   time
Date: 
Message-ID: <4395cd04$1@news.bezeqint.net>
Pascal Costanza wrote:
> 
> You could go through the metaobject protocol, but in this simple case I 
> would simply use eval to do this:
> 

Yes, this should work:

;;;;

(defmacro define-something (name &body body)
   `(progn
     (defparameter ,name (make-instance 'something))
     (eval '(defmethod foo ((obj (eql ,name)))
             ,@body))))

> You could also turn this into a function:

The real case behind this contrivance requires a macro.

Thank you.