>>>>> "Tim" == Tim Moore <mo...@herschel.bricoworks.com> writes:
Tim> On 23 May 2000, Tim Bradshaw wrote: >> * Tim Moore wrote: >> > How about a primary method on initialize-instance or shared-initialize? >> >> > (defmethod initialize-instance ((class abstract-class) &rest junk) >> > (declare (ignore junk)) >> > (error "Someone tried to make an instance of abstract-class!")) >> >> This makes all subclasses of ABSTRACT-CLASS noninstantiable, which is >> unlikely to be what you want.
Tim> Damn, you're right. Somehow I thought that a new initialize-instance Tim> method got defined for each class, but on further reflection that couldn't Tim> be right. Shows what I know.
Now I'm confused. Why wouldn't an initialize-instance specialized to a sub-class of abstract-class do the right thing? Only when there is no initialize-instance for the sub-class would the method for abstract-class be called and produce an error right?
* Raymond Toy wrote: >>>>>> "Tim" == Tim Moore <mo...@herschel.bricoworks.com> writes: > Now I'm confused. Why wouldn't an initialize-instance specialized to > a sub-class of abstract-class do the right thing? Only when there is > no initialize-instance for the sub-class would the method for > abstract-class be called and produce an error right?
Yes, but you can't write this method-of-the-subclass, because you don't know what it should do. The default primary method for INITIALIZE-INSTANCE is system-supplied, and although there's information about what it does (call SHARED-INITIALIZE), it's not clear to me that that is *all* it does. The obvious approach to overriding the default primary method would be something that at some point does (CALL-NEXT-METHOD) to make sure the default behaviour happens (or just define an :AFTER method in the normal way...), but this won't work in this case because you have to hop over (several levels of) superclass to actually get at the method you want to call.
Actually, I think I'm wrong about all this -- hyperspec Section 7.1.7 seems to mean that it is the case that all INITIALIZE-INSTANCE does is call SHARED-INITIALIZE, so you could define your own methods for it. (I guess I should elide all the previous para now...).
It would still be a bit clunky I think as you'd either have to do some cleverness with mixing classes (define a method signalling an error on ABSTRACT-CLASS, and one that does the default thing on NON-ABSTRACT-CLASS, then you can define non-abstract subclasses by ensuring NON-ABSTRACT-CLASS ends up ahead of ABSTRACT-CLASS in the CPL:
Barry Margolin <bar...@genuity.net> writes: > In article <m33dn89tfo....@alum.mit.edu>, > David Bakhash <ca...@alum.mit.edu> wrote: > >the real question here is "why do you think you need an abstract class > >in common lisp, and what do you think it would get you?"
> It's interesting to note that Flavors, one of the two main influences on > the design of CLOS, *did* have the notion of abstract classes. DEFFLAVOR > had an :ABSTRACT-FLAVOR option that indicated that the flavor couldn't be > instantiated by itself. It also had :REQUIRED-INSTANCE-VARIABLES and > :REQUIRED-METHODS, to declare that a flavor incorporating this flavor as a > base has to define these instance variables (what CLOS calls slots) and > methods, since methods in the base flavor will reference them > (:REQUIRED-METHODS is analogous to C++'s technique where the base class > declares a method with '= 0'). These things allow the base class to define > a protocol that mixins are supposed to implement.
> > You don't want to do this (why do I always get the feeling that > > the hardcore OO camp is living in a different dimension than I?), > > but here are a few statements that indicate that you can put > > such handcuffs on you if you use the mop:
> whoops, seems like Tim Bradshaw had already made an almost identical > posting that I missed at first sight - sorry about that...
Do you think this is enough? :{ Just wait for the objection "but this is a runtime and not a compile-time error!" :{
Cheers
-- Marco Antoniotti ===========================================
David Bakhash <ca...@alum.mit.edu> writes: > If you get caught trying to find rigorous analogies between CLOS and > (say) Java's object system, then you'll be troubled because in Java > (and C++), methods belong (and I think are lexically defined) inside > the classes to which they apply. Since methods belong to a paticular > class, they can't dispatch based on multiple classes (at least not > without ugly CASE-like statments or something).
Yes, in Java the methods are textually inside the class definitions.
Nonetheless, the existing Java syntax would work just fine for multi-arg dispatch.
(Indeed, if you know about the multi-arg dispatch, you'll find that some of the descriptions of how method lookup works in Java could remain unchanged. Because the authors never read what they wrote from the point of view of someone who might think all args were treated dynamically, they failed to see that their words did not make it clear that dynamic lookup *wasn't* what happened.)
> ... it's best to drop what you know and try learning CLOS with > an open mind. ...
Tim Bradshaw <t...@cley.com> writes: > * Frode Vatvedt Fjeld wrote: > > ... I'd guess that > > EQL-specialization is much faster than class-specialization, since it > > involves a single pointer comparison (I'm still guessing) rather than > > looking up some class hierarchy.
Any reasonable CLOS implementation would avoid any time-consuming lookup in the class hierarchy, at least most of the time. I'm not sure how sophisticated CLOS implementations get, but I'd expect them (a) to cache the results of any slow method lookup and (b) to use "special" dispatchers that "knew" something about what methods had been defined.
So for instance if all the specialisation was EQL, a dispatcher that handled that case efficiently could be installed.
Remember that for EQL-specialization, there might be different methods for different objects, just as their might be different methods for different classes. The chief difference is that to find the method based on the class of the argument, you have to extract the class of the argument, which could be as simple as one memory reference. (Even that might be avoided if the generic function thought it was going to see the same argument value often enough, since it could associate the method with the object rather than its class, rather as if the method had been EQL-specialised.)
> I'm not sure, I'd actually like to know this.
So would I. My guess is that less effort has been put into optimising the cases that involve EQL-specialisation.
Erik Naggum <e...@naggum.no> wrote: > On the contrary, this is really what we're looking for. In my view, > this is the only intelligent transposition of the "abstract class" > bullshit from the C++ world into areal object-oriented system, and > it shows that a fairly simple concept (generic functions) needs to > be reimplemented in a round-about, counter-intuitive way in an "OO" > system that fails to understand that classes do not "own" methods.
> "Abstract classes" do not have anything to do with the _classes_. > It's a misfeature of the encapsulation mechanism in C++ classes, > which is itself a misfeature of its implementation specifics and > its legacy from C and a misunderstanding of Simula's mechanisms.
Close, but not quite. An "abstract class" is closer to a protocol, i.e. a set of cooperating methods, than it is to a single method. This means that you'd need to define either a set of generic functions or my-abstract-class-protocol generic function that returns a defined set of functions.
Dan Pierson, Control Technology Corporation d...@control.com
* Dan L. Pierson <d...@control.com> | Close, but not quite. An "abstract class" is closer to a protocol, | i.e. a set of cooperating methods, than it is to a single method.
Huh? Obviously, you need more than one generic function if the abstract class defines more than one function that has to be implemented by the real classes. I'm not sure what you're arguing against, or possibly why you think this is non-obvious.
#:Erik -- If this is not what you expected, please alter your expectations.
In article <3168170036820...@naggum.no>, Erik Naggum <e...@naggum.no> wrote:
>* Dan L. Pierson <d...@control.com> >| Close, but not quite. An "abstract class" is closer to a protocol, >| i.e. a set of cooperating methods, than it is to a single method.
> Huh? Obviously, you need more than one generic function if the > abstract class defines more than one function that has to be > implemented by the real classes. I'm not sure what you're arguing > against, or possibly why you think this is non-obvious.
I'm not sure what you're arguing against, either.
Basically, in languages that have them, abstract classes are a way of encoding some rules about the protocol that the class hierarchy is intended to implement within the class definitions. In C++, you create an abstract class by defining a "pure virtual function" in the class, which is like Flavors's :REQUIRED-METHOD declaration; this indicates that classes in that hierarchy are required to implement that method, because some methods in the superclass will do the equivalent of (<method> self ...) or this-><method>(...). I think Java's "interface" classes are similar.
Most OO languages don't provide any way to define protocols in any rigorous fashion. I think Xerox PARC's research into Aspect-Oriented Programming tries to include this, but as far as established OO languages go, abstract classes and interface classes are about the only thing there is.
-- Barry Margolin, bar...@genuity.net Genuity, Burlington, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups. Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
>>>>> "Tim" == Tim Bradshaw <t...@cley.com> writes:
Tim> Yes, but you can't write this method-of-the-subclass, because you Tim> don't know what it should do. The default primary method for Tim> INITIALIZE-INSTANCE is system-supplied, and although there's Tim> information about what it does (call SHARED-INITIALIZE), it's not Tim> clear to me that that is *all* it does. The obvious approach to Tim> overriding the default primary method would be something that at some Tim> point does (CALL-NEXT-METHOD) to make sure the default behaviour Tim> happens (or just define an :AFTER method in the normal way...), but Tim> this won't work in this case because you have to hop over (several Tim> levels of) superclass to actually get at the method you want to call.
Tim> Actually, I think I'm wrong about all this -- hyperspec Section 7.1.7 Tim> seems to mean that it is the case that all INITIALIZE-INSTANCE does is Tim> call SHARED-INITIALIZE, so you could define your own methods for it. Tim> (I guess I should elide all the previous para now...).
Yes, if I delete that paragraph, I feel much better about my limited understanding of CLOS---I wasn't totally off base. :-)
Tim> It would still be a bit clunky I think as you'd either have to do some Tim> cleverness with mixing classes (define a method signalling an error on Tim> ABSTRACT-CLASS, and one that does the default thing on Tim> NON-ABSTRACT-CLASS, then you can define non-abstract subclasses by Tim> ensuring NON-ABSTRACT-CLASS ends up ahead of ABSTRACT-CLASS in the Tim> CPL:
Tim> ) or define lots of methods for INITIALIZE-INSTANCE for all the Tim> subclasses.
Yes, this sounds quite messy if you really want to use abstract-class with multiple-inheritance. Fortunately, I haven't had any reason to go down that path with my CLOS stuff.
Barry Margolin <bar...@genuity.net> writes: > Basically, in languages that have them, abstract classes are a way > of encoding some rules about the protocol that the class hierarchy > is intended to implement within the class definitions. In C++, you > create an abstract class by defining a "pure virtual function" in > the class, which is like Flavors's :REQUIRED-METHOD declaration; > this indicates that classes in that hierarchy are required to > implement that method, because some methods in the superclass will > do the equivalent of (<method> self ...) or this-><method>(...). I > think Java's "interface" classes are similar.
How does this work in Flavors? I am very unfamiliar with Flavors. Are method definitions lexically connected with class definitions? If not, how would the system know when to say, "Hey buddy, you forgot this required method!"
In CLOS this doesn't make much sense unless you wanna add a method which uses the MOP to scan a set of generic functions to make sure they have a method specialized on a given class. But when do you wanna run that code? At the end of your system load or something? I suppose that would be of some use.
-- Craig Brozefsky <cr...@red-bean.com> Lisp Web Dev List http://www.red-bean.com/lispweb --- The only good lisper is a coding lisper. ---
>> Basically, in languages that have them, abstract classes are a way >> of encoding some rules about the protocol that the class hierarchy >> is intended to implement within the class definitions. In C++, you >> create an abstract class by defining a "pure virtual function" in >> the class, which is like Flavors's :REQUIRED-METHOD declaration; >> this indicates that classes in that hierarchy are required to >> implement that method, because some methods in the superclass will >> do the equivalent of (<method> self ...) or this-><method>(...). I >> think Java's "interface" classes are similar.
>How does this work in Flavors? I am very unfamiliar with Flavors. >Are method definitions lexically connected with class definitions? If >not, how would the system know when to say, "Hey buddy, you forgot >this required method!"
Although Flavors associates methods with specific flavors, like most other OO languages, it's like CLOS in that methods are not lexically part of the flavor definition. The Chinual says "This keyword allows the error of having no handler for the message to be detected when the flavor is defined (which usually means at compile time) rather than at run time."
>In CLOS this doesn't make much sense unless you wanna add a method >which uses the MOP to scan a set of generic functions to make sure >they have a method specialized on a given class. But when do you >wanna run that code? At the end of your system load or something? I >suppose that would be of some use.
Flavors has a macro (compile-flavor-methods &rest flavor-names) that can be put in a file to be compiled. When this form is compiled, all the combined methods are genated and put into the resulting object file. I think this will perform the :REQUIRED-METHOD consistency checking. If you don't use this, then the consistency checking will indeed be deferred to run-time, the first time an instance of a sub-flavor is instantiated.
I think most CLOS implementations have something that's analogous to this, to precompile its data structures.
-- Barry Margolin, bar...@genuity.net Genuity, Burlington, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups. Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
In article <87d7main2l....@piracy.red-bean.com>, Craig Brozefsky <cr...@red-bean.com> writes:
> ... > In CLOS this doesn't make much sense unless you wanna add a method > which uses the MOP to scan a set of generic functions to make sure > they have a method specialized on a given class. But when do you
CLOS'es object model doesn't exactly tie methods to one class.
> wanna run that code? At the end of your system load or something? I > suppose that would be of some use.