[closer-devel] Introducing new "type" classes

Marco Antoniotti marcoxa at cs.nyu.edu
Tue Feb 19 14:18:26 UTC 2008


On Feb 17, 2008, at 19:08 , Pascal Costanza wrote:
>
>
>> For classes and EQL specializers you have a notion, but why should  
>> this not be hammered into a subset relationship, ANSI 4.2.2 "Type  
>> Relationships" notwithstanding?
>>
>> Given that SATIFIES is a no-no in any case when wanting to do  
>> something useful with types (at least w.r.t. compilation: Python  
>> does not deal with SATISFIES and, last I checked, AND types are  
>> dealt with in a limited way) and that therefore we can readily  
>> hide it under the carpet for the time being, we have that (integer  
>> 1 10) is a subset of (integer 0 *), thus I would consider it more  
>> specific.  The issues really start when you deal with  
>> intersections, e.g.
>>
>> (defmethod foo ((i (integer 0 100))) ...)
>> (defmethod foo ((j (integer 32 1024))) ...)
>>
>> (foo 42)
>>
>> But even in this case you could raise an error at (re)definition  
>> time because you are defining a method which would require a  
>> runtime choice (in the above example at the definition time of the  
>> second FOO method).
>>
>> Am I making sense or is there a hole somewhere?  Are there type  
>> subset tests that could not be made at (re)definition time?
>
> Hm. could make sense.
>
> Thinking out aloud again: You could even defer the error to  
> invocation time, because maybe the conflict never arises. (Hmm,  
> hmm... ;)

Yes, but I would not allow that.  First of all I think it is easier  
to check for these things at (re)definition time, secondly, I believe  
in helping the compiler and letting it help me (as an aside, I am  
nonplussed by the comment "don't lie to the compiler" comment you get  
sometime).


> Another issue that may come up: The idea of using classes for  
> dispatch is interesting because it gives you pretty good  
> efficiency. Method dispatch works by looking at the classes of all  
> the required arguments, and looking up applicable methods for those  
> classes. This can be implemented very efficiently, both in terms of  
> space and lookup time. Eql specializers already make that a bit  
> harder, and subset relationships could be even more problematic.  
> (But maybe not...)
>
> In my personal opinion, I think the protocol for eql specializers  
> is misdesigned anyway. Whenever defmethod sees an (eql xyz) form,  
> it turns it into an instance of eql-specializer, and such instances  
> are used for method lookup. Since eql-specializers are so different  
> from class specializers, the lookup has to be split into two  
> different steps, compute-applicable-methods-using-classes and  
> compute-applicable-methods. C-a-m-u-c signals an 'error' in case  
> classes are not sufficient to determine method applicability. I  
> think there is a lost opportunity for having a more streamlined  
> protocol.
>
> What I would envision is something like this: An eql-specializer  
> could actually be an instance of a class generated on the fly which  
> is a subclass of the class of the object in question. So, say, you  
> have the following definitions:
>
> (defclass person (...) ...)
>
> (defvar *a-person* (make-instance 'person ...))
>
> (defmethod foo ((obj (eql *a-person*))) ...)
>
> The idea is that (intern-eql-specializer *a-person*) should return  
> an object whose class is a generated subclass of person.

Yes.  That is what I had in mind as well.  Note that your example is  
a little misleading.  If next I do

(setf *a-person* (make-instance 'person))

(foo *a-person*)

I get an error.

This means that the generation on the fly of the singleton classes is  
warranted.  But for subset relationships you have to jump through a  
number of hoops, as you cannot subclass INTEGER etc etc.

>
> This would allow for having a single generic function compute- 
> applicable-methods-using-specializer, instead of two separate ones.  
> In order to perform method dispatch, the discriminating function  
> would have to look for the specializers of the objects, not the  
> classes. Roughly as follows:
>
> (defmethod compute-discriminating-function ((gf standard-generic- 
> function))
>   (lambda (&rest args)
>     (let* ((specializers (mapcar #'specializer-of args))
>            (applicables  (compute-applicable-methods-using- 
> specializers gf specializers))
>            (effective-method (compute-effective-method gf (generic- 
> function-method-combination gf) applicables))
>            (effective-metod-function (compute-effective-method- 
> function gf effective-method)))
>       (apply effective-method-function args))))
>
> The hard part would be to find an efficient implementation for  
> specializer-of. One idea would be to add a tag bit to objects that  
> indicate whether they are used as eql specializers anywhere in a  
> system, and if that tag bit is not set, specializer-of can just be  
> implemented with class-of, otherwise it will call intern-eql- 
> specializer. If on top of that, specializer-of is a generic  
> function, one could then maybe add functionalities like dispatching  
> on set types, as you suggest, for one's own generic function classes.

I think I lost you here....  AFAIU, why should you not make  
SPECIALIZER-OF dependent on the GF as well?  That would seem to me to  
be the right anchor for this kind of information.

>
> That's a very rough idea, there are probably a couple of devils in  
> the details...
>
> Just brainstorming...

Of course...  but maybe something interesting will come out of it.

Cheers

Marco

PS.  Can you point me in the direction of the papers by Chris and Jim?




More information about the closer-devel mailing list