Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CLOS address superclass constructor (lisp newbie)

44 views
Skip to first unread message

David Greene

unread,
Jul 30, 2009, 3:08:29 PM7/30/09
to
I don't know if this is possible in the CLOS lisp? How to I "fire" the
initialize method of a "superclass"?

In c# it's easy...
Obviously this is usually considered redundant in c#.

public class SomeClass : SomeSuperClass
{
public SomeClass
: base ( ) // SomeSuperClass constructor fired explicitly.
{
// do whatever
}
}


Essentially same thing in PHP
I don't really know how redundant this is in PHP but I always do it.

class SomeClass extends SomeSuperClass
{
function __construct( $form_args )
{
parent::__construct( $form_args );

// do whatever
}
}

I understand that:
(defmethod initialize-instance ((this SomeClass) &rest initargs) #| do
whatever |# )

is not quite the same thing. I know about the :before :after junk but that
doesn't seem to make sense... Especially if I have several "layers" of
superclasses. In theory what I want is to be sure the call to the immediate
superclass initialize-instance and that superclass "fires" whatever it has
to. Generally speaking down to the "super" superclass.

I'm also not using init-form stuff on the slots because I don't want to. I
would prefer to use initialize-instance and do what I want in that method.
Unless I am doing something wrong the "SomeSuperClass" initialize-instance
is not firing. I know that is what is supposed to happen and in fact I
depend on it. What I don't understand is how to I use the superclasses
method if I want to.

Most of the time when I set up my classes there are things that I want the
superclass to handle, usually when I override a particular method it is to
"augment" the superclasses behavior for that particular method. I don't
really want to have to completely re-write or duplicate the superclasses
method before I can do anything.

Obviously, sometimes I do, in fact, want to completely override the base
class's behavior.

How can I address or call a particular superclasses "base" function in an
overwritten function? I'm hoping it's something stupid I missed because of
course I would like call the superclass base function at a time of my
choosing.


Rainer Joswig

unread,
Jul 30, 2009, 3:55:11 PM7/30/09
to
On 30 Jul., 21:08, "David Greene" <D...@NoWhere.com> wrote:
> I don't know if this is possible in the CLOS lisp? How to I "fire" the
> initialize method of a "superclass"?

...

> How can I address or call a particular superclasses "base" function in an
> overwritten function? I'm hoping it's something stupid I missed because of
> course I would like call the superclass base function at a time of my
> choosing.

Methods don't belong to classes in CLOS.

Read a CLOS tutorial: http://cl-cookbook.sourceforge.net/clos-tutorial/index.html

See also the chapters on Object Reorientation: http://gigamonkeys.com/book/

For your problem, see CALL-NEXT-METHOD
http://www.lispworks.com/documentation/HyperSpec/Body/f_call_n.htm

Alberto Riva

unread,
Jul 31, 2009, 12:56:53 AM7/31/09
to
David Greene wrote:
> I don't know if this is possible in the CLOS lisp? How to I "fire" the
> initialize method of a "superclass"?
>
> In c# it's easy...

[inscrutable sequence of weird-looking symbols elided]

> I understand that:
> (defmethod initialize-instance ((this SomeClass) &rest initargs) #| do
> whatever |# )
>
> is not quite the same thing. I know about the :before :after junk but that
> doesn't seem to make sense... Especially if I have several "layers" of
> superclasses.

If you have multiple applicable :before or :after methods, they all get
called, in the "right" order. This is actually how INITIALIZE-INSTANCE
should be used: it's not a good idea to redefine the primary method as
you did above, but you should feel free to define :after methods on it
to perform whatever additional initialization you need on your
instances. And if you have multiple :after methods defined in your
superclass hierarchy, they will *all* be executed (least specific first).

So, it seems that this would do what you need, and you don't even have
to worry about invoking "super" methods explicitly.

> I'm also not using init-form stuff on the slots because I don't want to. I
> would prefer to use initialize-instance and do what I want in that method.

Could you please explain this? Any particular reason why don't you want
to use initforms?

> How can I address or call a particular superclasses "base" function in an
> overwritten function?

As Rainer pointed out, in general you would use CALL-NEXT-METHOD.

Alberto

David Greene

unread,
Jul 31, 2009, 6:48:32 AM7/31/09
to

"Alberto Riva" <ar...@nospam.ufl.edu> wrote in message
news:h4ttav$d70$1...@usenet.osg.ufl.edu...

Thanks - I didn't understand the :after :before methods worked like that. I
swapped out my initialize-instance to initialize-instance :after and got the
results that I'm used to. I did once try the :before part because based on
my experience in other languages it seemed to make more sense somehow.
Anyway :before failed so I made the erroneous assumption that all that stuff
made no sense.

>> I'm also not using init-form stuff on the slots because I don't want to.
>> I would prefer to use initialize-instance and do what I want in that
>> method.
>
> Could you please explain this? Any particular reason why don't you want to
> use initforms?

Habit mostly... and even in c# there are ways of running "macros" or telling
the compiler to insert a bunch of stuff that you can't really see the actual
code the compiler is compiling. I prefer to be as explicit as possible in
the lexical writing of my code so I don't have to figure out what code the
compiler is actually compiling. I am aware that defclass is a macro as is
defmethod and a wide range of "calls" made in lisp. It is for this reason,
at this point, that I want to eliminate as much as possible the "stuff" that
the macro injects into my program. As I become more experienced I may well
be comfortable/knowledgeable enough to use the various "slot switches" to my
benefit.


>> How can I address or call a particular superclasses "base" function in an
>> overwritten function?
>
> As Rainer pointed out, in general you would use CALL-NEXT-METHOD.

If I understand the CALL-NEXT-METHOD "stuff" it REQUIRES :before and :after
stuff on the function in question. What my question was is... How can I
address the parent/overridden function. This usually requires some sort of
"casting" of the "this"(self?) pointer. I don't know what lispers like to
call it in most documentation it is some kind of a horrid thing to lexically
call it the "this" or "self" pointer. Anyway usually there is some way to
"cast" the this pointer to a pointer that can be used to explicitly call
methods of the "base" class.


Rainer Joswig

unread,
Jul 31, 2009, 7:24:49 AM7/31/09
to
On 31 Jul., 12:48, "David Greene" <D...@NoWhere.com> wrote:

...

> >> How can I address or call a particular superclasses "base" function in an
> >> overwritten function?
>
> > As Rainer pointed out, in general you would use CALL-NEXT-METHOD.
>
> If I understand the CALL-NEXT-METHOD "stuff" it REQUIRES :before and :after
> stuff on the function in question. What my question was is... How can I
> address the parent/overridden function. This usually requires some sort of
> "casting" of the "this"(self?) pointer. I don't know what lispers like to
> call it in most documentation it is some kind of a horrid thing to lexically
> call it the "this" or "self" pointer. Anyway usually there is some way to
> "cast" the this pointer to a pointer that can be used to explicitly call
> methods of the "base" class.

Methods don't belong to classes.

A small domain: ships and boats can collide and sink if damaged.

(defclass thing () ())

(defclass ship (thing) ())
(defclass container-ship (ship) ())
(defclass island (thing) ())
(defclass boat (thing) ())

; m1
(defmethod collide ((object1 thing) (object2 thing))
(format t "~a and ~a are colliding" object1 object2))

; m2
(defmethod collide ((object1 ship) (object2 thing))
(damage object1)
(damage object2))

; m3
(defmethod collide ((object1 ship) (object2 boat))
(call-next-method)
(when (severe-damage-p object2)
(sink object2)))

There is no 'self'. COLLIDE takes two objects.

(collide (make-instance 'ship) (make-instance 'boat))

The most specific primary method will be called. CALL-NEXT-METHOD
calls the next specific (inherited) method.

First m3, m3 calls m2 via CALL-NEXT-METHOD, M1 is not called.

As you can see CLOS looks at all arguments. Here the second argument
makes the difference, because we pass a boat.

Let's change M1 to an :around method:

; new m1
(defmethod collide :around ((object1 thing) (object2 thing))
(format t "~a and ~a are colliding" object1 object2)
(call-next-method))

Now:

First 'new m1' gets called, then it calls m3, which then calls m2.


Since CLOS/Common Lisp is quite different from most other object
oriented languages, there is no chance to transfer any C#/Java/
Smalltalk/Ruby/Python/... knowledge without actually reading a bit
about CLOS.

David Greene

unread,
Jul 31, 2009, 8:54:53 AM7/31/09
to

"Rainer Joswig" <jos...@lisp.de> wrote in message
news:def1d5b2-978a-4a33...@r38g2000yqn.googlegroups.com...

> On 31 Jul., 12:48, "David Greene" <D...@NoWhere.com> wrote:
> ...
>

I don't know how to reply to this. There is NOTHING you present that can't
be done in other OO languages. You immediatly present a method that deals
with two seperate classes and the method parameters reflect this fact
explicitly. Technically methods don't "belong" to classes in any language.
It lexically appears that way in other languages and in fact it is
difficult(possibly not doable) to make an object's method outside of the
lexical appearence in other languages.

I understand what you mean but, it still fails to address the question at
point here in this thread... How can the "base"/"immediate superclass" be
addressed explicitly in CLOS.

I'm not sure but, your example just server to show the lexical difference
betweem CLOS and other OOP's. In CLOS the current instance is refered to
(this class) vs in other OOP's it is lexically "clearer" class.method() . Or
some lexical equivelant to parentclass::method() when overriding a method.

> (when (severe-damage-p object2)
> (sink object2)))

Is very interesting and I have seen it before... What I haven't seen is when
I know what the base class is because I'm in the subclass... How do I
address the superclass.

Apparently it isn't known by lispers but it's not a good idea to override a
superclasses method unless you explicitly call that method either before or
after you done what you need to do. There is nothing new here. In CLOS it is
called the "primary method" in other languages that's all there is... It's
great there is more in CLOS. I have found that :after works in a way that I
am used to. However the warning that you should't override the "primary
method" actually holds true in any OOP language that I am aware of. The
difference is generally "constuctors" or "destructors" in other OOP
languages an explicit call the "base" function is redundant because the
language or compiler for the language does it automatically. However outside
of "constuctors" or "destructors" it is quite common to have to explicitly
make this call yourself.

So far the question is still unanswered... How do I "cast" the "this"
pointer to a pointer that can explicitly call the underlying method?


Pascal J. Bourguignon

unread,
Jul 31, 2009, 9:13:06 AM7/31/09
to
"David Greene" <Da...@NoWhere.com> writes:

> "Rainer Joswig" <jos...@lisp.de> wrote in message
> news:def1d5b2-978a-4a33...@r38g2000yqn.googlegroups.com...
>> On 31 Jul., 12:48, "David Greene" <D...@NoWhere.com> wrote:
>> ...
>>
>> Methods don't belong to classes.

CLOS / \ (They belong to generic functions).

>> [...]


>>
>> Since CLOS/Common Lisp is quite different from most other object
>> oriented languages, there is no chance to transfer any C#/Java/
>> Smalltalk/Ruby/Python/... knowledge without actually reading a bit
>> about CLOS.
>
> I don't know how to reply to this. There is NOTHING you present that can't
> be done in other OO languages. You immediatly present a method that deals
> with two seperate classes and the method parameters reflect this fact
> explicitly. Technically methods don't "belong" to classes in any language.

This last sentence is wrong. To take a simple example, Objective-C,
show me how you can create a new method without having it attached to
a class:
http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

AFAIK it is the same in all other OO programming languages but CLOS.


> It lexically appears that way in other languages and in fact it is
> difficult(possibly not doable) to make an object's method outside of the
> lexical appearence in other languages.

It has nothing to do with lexical source. In Objective-C, like in
Smalltalk, you can create methods at run-time. But you cannot create
a method without having a class to own it.

> I understand what you mean but, it still fails to address the question at
> point here in this thread... How can the "base"/"immediate superclass" be
> addressed explicitly in CLOS.
>
> I'm not sure but, your example just server to show the lexical difference
> betweem CLOS and other OOP's. In CLOS the current instance is refered to
> (this class) vs in other OOP's it is lexically "clearer" class.method() . Or
> some lexical equivelant to parentclass::method() when overriding a method.


>> (when (severe-damage-p object2)
>> (sink object2)))
>
> Is very interesting and I have seen it before... What I haven't seen is when
> I know what the base class is because I'm in the subclass... How do I
> address the superclass.
>
> Apparently it isn't known by lispers but it's not a good idea to override a
> superclasses method unless you explicitly call that method either before or
> after you done what you need to do. There is nothing new here.

What is good is the Lyskov Substitution Principle. The rest is up to
the contract between the superclasses and the subclasses.

Remember that there are several superclasses.


> So far the question is still unanswered... How do I "cast" the "this"
> pointer to a pointer that can explicitly call the underlying method?

You cannot, because there is not one superclass, and there are these
before and after and other kind of methods. These methods belong to
the generic function, and only the generic function may know what is
the next method to be called. So you use (when (next-method-p)
(call-next-method)) and don't bother with the superclasses.

Notice in the case of C++, when you have multiple-inheritance, you
have to call all the methods in the superclasses in each method of the
subclasses, and you have to determine in each case in what order you
will call them.

In the case of CLOS, the generic functions implement a standard
algorithm, used for all methods, to determine in which order the
methods of the superclasses are called by call-next-method, depending
on the order of the class precedence list (depending on the arguments
of the generic function, and the order in which superclasses are
listed in the defclass form).

--
__Pascal Bourguignon__

Paul Foley

unread,
Jul 31, 2009, 10:01:19 AM7/31/09
to
"David Greene" <Da...@NoWhere.com> writes:

> I'm not sure but, your example just server to show the lexical difference
> betweem CLOS and other OOP's. In CLOS the current instance is refered to
> (this class) vs in other OOP's it is lexically "clearer" class.method() . Or

But when you have two objects, in CLOS you can write (foo arg1 arg2);
in your supposedly "clearer" language, would you like to write
(arg1,arg2).foo() or something?

> Is very interesting and I have seen it before... What I haven't seen is when
> I know what the base class is because I'm in the subclass... How do I
> address the superclass.

There is no "the" superclass -- we have multiple inheritance!

Say you have

(defclass Foo (A B C) ...)

(defmethod bar ((this Foo))
YOUR-THING-HERE)

without any further information, what would you write for
"YOUR-THING-HERE", if you could use your parent::method(...) syntax?
A::bar(this), B::bar(this) or C::bar(this)? How do you know which one
implements the bar method? OK, you can be expected to know that or you
wouldn't be inheriting from them, but what if they all do?...then
you write

(defmethod bar ((this Foo))
...
(A::bar this)
...)

and the definition of A::bar has to look something like

(defmethod bar ((this A))
...
(B::bar this)
...)

but B isn't a superclass of A!

(OK, you say, you'll write

(defmethod bar ((this Foo))
...
(A::bar this)
(B::bar this)
(C::bar this)
...)

so that A::bar doesn't have to call B::bar, and that'll fix the
problem. But what if A, B and C (or any two of them) have a
superclass D in common? Then A::bar will call D::bar, and B::bar will
call D::bar...and it gets called three times, instead of once!)


CALL-NEXT-METHOD does the right thing. Just use it!

Rainer Joswig

unread,
Jul 31, 2009, 10:09:07 AM7/31/09
to
On 31 Jul., 14:54, "David Greene" <D...@NoWhere.com> wrote:

> Since CLOS/Common Lisp is quite different from most other object
> > oriented languages, there is no chance to transfer any C#/Java/
> > Smalltalk/Ruby/Python/... knowledge without actually reading a bit
> > about CLOS.
>
> I don't know how to reply to this. There is NOTHING you present that can't
> be done in other OO languages. You immediatly present a method that deals
> with two seperate classes and the method parameters reflect this fact
> explicitly.

This is already a huge difference. Common Lisp supports multi-methods.
Dispatch works over all arguments. Most languages don't support that
(note that in C++ it may look similar, but C++ also does not do multi-
dispatch).

> Technically methods don't "belong" to classes in any language.
> It lexically appears that way in other languages and in fact it is
> difficult(possibly not doable) to make an object's method outside of the
> lexical appearence in other languages.

There are other languages where methods are defined lexically outside
of classes, but the method provides a scope where for example the
slots can be accessed directly. Common Lisp does not do that. Generic
functions are independent of classes, there is no special scope for
slots, etc.

> I understand what you mean but, it still fails to address the question at
> point here in this thread... How can the "base"/"immediate superclass" be
> addressed explicitly in CLOS.

The last sentence makes no sense in CLOS. In CLOS methods don't belong
to classes and objects directly contain all slots (of their class and
the superclasses).


>
> I'm not sure but, your example just server to show the lexical difference
> betweem CLOS and other OOP's. In CLOS the current instance is refered to
> (this class) vs in other OOP's it is lexically "clearer" class.method() . Or
> some lexical equivelant to parentclass::method() when overriding a method.

The difference is that a CLOS method gets a bunch of objects passed.

(print-me document printer)

Both printer and document are objects. neither of those objects is
THIS. How you name your parameters is totally your own task.

(defmethod print-me ((a-document document) (a-printer printer))
...)

is totally equivalent to

(defmethod print-me ((this document) (there printer))
...)

Since two objects are passed, dispatch works over both objects, CLOS
does not say which is this or that. You name the parameter and that's
it.
The local variables are: a-document, a-printer in the first method;
this, there in the scecond method.

> Is very interesting and I have seen it before... What I haven't seen is when
> I know what the base class is because I'm in the subclass... How do I
> address the superclass.

'You' are not in the subclass. Methods are not in classes.

> Apparently it isn't known by lispers but it's not a good idea to override a
> superclasses method unless you explicitly call that method either before or
> after you done what you need to do.

It is part of the 'object reorientation' to get rid of such common
wisdom when you use CLOS.

> There is nothing new here. In CLOS it is
> called the "primary method" in other languages that's all there is... It's
> great there is more in CLOS. I have found that :after works in a way that I
> am used to. However the warning that you should't override the "primary
> method" actually holds true in any OOP language that I am aware of.

CLOS is not really that way. It is more dynamic. The code that runs at
runtime when you call a function is not fixed. It depends on the class
hierarchy (which is dynamic), the objects and the available methods
(there are different method types: around, before, after, primary). So
you don't program a fixed class hierarchy (of classes and their
superclasses), but conceptually you provide a bunch of methods that do
something and the Lisp runtime chooses the right ones at runtime and
executes one or more of them with the provided arguments.

> The
> difference is generally "constuctors" or "destructors" in other OOP
> languages an explicit call the "base" function is redundant because the
> language or compiler for the language does it automatically. However outside
> of "constuctors" or "destructors" it is quite common to have to explicitly
> make this call yourself.

In CLOS there is no special mechanism for constructors and there are
no destructors. INITIALIZE-INSTANCE is a normal generic function, for
which you can provide methods and you can call inherited methods by
CALL-NEXT-METHOD.

>
> So far the question is still unanswered... How do I "cast" the "this"
> pointer to a pointer that can explicitly call the underlying method?

Have you tried to use CALL-NEXT-METHOD yet?

David Greene

unread,
Jul 31, 2009, 10:56:23 AM7/31/09
to

"Paul Foley (http://public.xdi.org/=pf)" <s...@below.invalid> wrote in
message news:m2y6q5d...@wyoming.home...

> "David Greene" <Da...@NoWhere.com> writes:
> CALL-NEXT-METHOD does the right thing. Just use it!

Sorry guys... I didn't mean to be obtuse... I swapped out the
initialize-instance :after and added (call-next-method) as the first line in
initialize-instance and all runs as expected. It's just that call NEXT
method seems so weird? In my head there is no NEXT method only previously
defined methods in x number of superclasses.

If I may suggest for CLOS newbie's from other OOP languages... All the other
stuff for me is yet to be discovered. In order to last long enough to
discover it I need to be able to write in a fashion at least a little
familiar with what I am used to. I don't want or mean to be ungrateful,
thank you both very much, but jumping on there is no this pointer is really
hard to grasp. Or that methods don't belong to classes it true but, not
terribly helpful for a newbie. I know that it's somewhat dangerous to make a
newbie think something that isn't quite accurate is problematic for the
newbie down the road. On the other hand if the newbie gets so confused as to
give up the attempt it serves no one's interest either.

(call-next-method) Is so "lexically upside-down and backwards" from other
OOP's that there must be some better way to explain it? Some way that allows
the newbie to fumble on while making clear that it's not the same.

I am assuming that (call-next-method) is pretty "universal" when overriding
a "primary method". Or as is the warning in other oop languages "Warning do
not override a method without calling" (call-next-method) "either in the
first line of your method but almost certainly before the end of your
method". Notice the almost certainly, as we all know "completely shorting
out" the underlying method might be the object of the exercise!

Again... Thank you both for your time!


Rainer Joswig

unread,
Jul 31, 2009, 11:35:11 AM7/31/09
to
On 31 Jul., 16:56, "David Greene" <D...@NoWhere.com> wrote:
> "Paul Foley (http://public.xdi.org/=pf)" <s...@below.invalid> wrote in
> messagenews:m2y6q5d...@wyoming.home...
>

As I said, and I don't mean it negative, be prepared that a few things
really are different. There is an old saying that you can learn Lisp
in a day, unless you know Fortran, then you need more time. It is
similar here.

If we work with other object-oriented languages we think of a class
HIERARCHY. We can reference a superclass.

Not in CLOS. In CLOS the methods are in a SORTED LIST.

The basic model is as follows:

a) you have a bunch of methods, say, for the generic function COLLIDE

method | class1 | class2
------------------------
COLLIDE ship boat
COLLIDE thing thing
COLLIDE ship island
COLLIDE ship thing

b) now you call COLLIDE with a ship and a boat

(collide a-ship a-boat)

CLOS looks which methods are applicable

method | class1 | class2 | applicable
-------------------------------------
COLLIDE ship boat yes
COLLIDE thing thing yes
COLLIDE ship island no a boat is not an island
COLLIDE ship thing yes

c) CLOS sorts the applicable methods

method | class1 | class2 | pos
-------------------------------------
COLLIDE ship boat 1 boat is more specific than
thing
COLLIDE ship thing 2 ship is more specific than
thing
COLLIDE thing thing 3

So the methods are sorted and the most specific method is FIRST.

d) CLOS calls the FIRST method

method | class1 | class2 | pos | current
----------------------------------------
COLLIDE ship boat 1 <-
COLLIDE ship thing 2
COLLIDE thing thing 3

Now method number TWO is the NEXT method.
Now, CALL-NEXT-METHOD just calls the next one, number two.

method | class1 | class2 | pos | current
----------------------------------------
COLLIDE ship boat 1
COLLIDE ship thing 2 <-
COLLIDE thing thing 3

Now we are in method two, CALL-NEXT-METHOD then calls the next one:
number three

method | class1 | class2 | pos | current
----------------------------------------
COLLIDE ship boat 1
COLLIDE ship thing 2
COLLIDE thing thing 3 <-

After method 3 there is no other method, calling the next method is an
error.

>
> Again... Thank you both for your time!

:-)

Duane Rettig

unread,
Jul 31, 2009, 12:07:59 PM7/31/09
to
On Jul 31, 7:56 am, "David Greene" <D...@NoWhere.com> wrote:
> "Paul Foley (http://public.xdi.org/=pf)" <s...@below.invalid> wrote in
> messagenews:m2y6q5d...@wyoming.home...

>
> > "David Greene" <D...@NoWhere.com> writes:
> > CALL-NEXT-METHOD does the right thing.  Just use it!
>
> Sorry guys... I didn't mean to be obtuse... I swapped out the
> initialize-instance :after and added (call-next-method) as the first line in
> initialize-instance and all runs as expected. It's just that call NEXT
> method seems so weird? In my head there is no NEXT method only previously
> defined methods in x number of superclasses.

It's all based on point-of-reference. If you think "next" is
backwards, perhaps you're facing the wrong direction. If you look at
the hierarchy of calling in CLOS methods, it is generally most-
specific-to-less-specific from the beginning of the generic function
(note that :after methods are opposite, but those are run on the way
out of the generic function). So in places where call-next-method
would be used. "next" will refer to the more general, or less specific
method, which is the next applicable method by way of the class-
precedence list.

Why do I harp on this seemingly minor terminology issue, when you seem
to have finally understood what others were telling you? Well...

> If I may suggest for CLOS newbie's from other OOP languages... All the other
> stuff for me is yet to be discovered. In order to last long enough to
> discover it I need to be able to write in a fashion at least a little
> familiar with what I am used to.

I urge you to resist that temptation. Like the "next" terminology, if
you try to wrap your own prior understanding of Oop around CLOS, you
will only continue to confuse yourself; everything will seem
backwards.

I don't want or mean to be ungrateful,
> thank you both very much, but jumping on there is no this pointer is really
> hard to grasp. Or that methods don't belong to classes it true but, not
> terribly helpful for a newbie. I know that it's somewhat dangerous to make a
> newbie think something that isn't quite accurate is problematic for the
> newbie down the road. On the other hand if the newbie gets so confused as to
> give up the attempt it serves no one's interest either.

Being a newbie isn't the problem; it's being a newbie to CLOS having
already endured the baggage of other Oop systems that is the problem.
You must unlearn a certain amount of other-oop before you can truly
understand CLOS, and to a certain extent, Lisp itself.

> (call-next-method) Is so "lexically upside-down and backwards" from other
> OOP's that there must be some better way to explain it? Some way that allows
> the newbie to fumble on while making clear that it's not the same.

Again: newbies in general don't have as much of a problem with CLOS -
its lisp-newbies with baggage that needs to be unlearned that have the
trouble. The only suggestion I can give you is to recognize a
paradigm-shift, and accept it, keeping an open mind for anything which
seems bizarre wrt other thought models, but which (if you can truly
keep that open mind) makes perfect sense for the Common Lisp/CLOS
model.

> I am assuming that (call-next-method) is pretty "universal" when overriding
> a "primary method". Or as is the warning in other oop languages "Warning do
> not override a method without calling" (call-next-method) "either in the
> first line of your method but almost certainly before the end of your
> method". Notice the almost certainly, as we all know "completely shorting
> out" the underlying method might be the object of the exercise!

One of the hallmarks of Common Lisp is its openness, and the
willingness to give you enough rope to hang yourself. Can you handle
that much power? It remains to be seen. As for making a rule for
call-next-method invocation; many times the reasons for the rules are
arcane, and often people can't tell you why it is a rule; "the
language tells me not to do this, so I don't". But if you create
such a rule for yourself, and then see a place where someone has
apparently thumbed their nose at your rule, and yet the software works
perfectly well, then what are you going to think about that? Or, even
worse, what happens when you need to break your own rule? Will you
remember back to this time, when the reason for always using call-next-
method was purely to do it the same way other languages do it? It is
actually likely that you would not be harmed much by making such a
rule for yourself; it would simply limit how far you could go in your
programming experience with CL/CLOS. And the irony is that you would
not know how much you were limiting yourself, because you would be
happily programming in your own subset of CL where your rules apply.
But know this: this type of rule doesn't apply precisely because CL
strives to be an open language, and to enable to do things in many
different ways, including ways that are restricted in other languages.

Duane


Pascal J. Bourguignon

unread,
Jul 31, 2009, 12:35:40 PM7/31/09
to
Rainer Joswig <jos...@lisp.de> writes:
> CLOS looks which methods are applicable
>
> method | class1 | class2 | applicable
> -------------------------------------
> COLLIDE ship boat yes
> COLLIDE thing thing yes
> COLLIDE ship island no a boat is not an island
> COLLIDE ship thing yes
>
> c) CLOS sorts the applicable methods
>
> method | class1 | class2 | pos
> -------------------------------------
> COLLIDE ship boat 1 boat is more specific than thing
> COLLIDE ship thing 2 ship is more specific than thing
> COLLIDE thing thing 3
>
> So the methods are sorted and the most specific method is FIRST.

Very good description!

--
__Pascal Bourguignon__

David Greene

unread,
Jul 31, 2009, 12:42:15 PM7/31/09
to
Thanks-

It almost seems like we are talking about compiled vs uncompiled stuff? I
don't know if I can say what I want coherently. I have clearly missed the
mark in my previous posts about OOP.

In c# there are multi-functions as well:

assume we are lexically within some class:

foo( int x ) { /* do something with the int */ }
foo( string x ) { /* do something with a string */ }

I can now call classx.foo( 1 ); and the integer function will be called. On
the other hand I can also call classx.foo( "hello" ); and classx will do
something with the string.

Now the c# compiler "figures out" which function to call, I use this
"feature" all the time. I think you are saying that lisp has the same
"feature" because the list of "possible functions" is a list of functions
ordered in a "push stack fashion" or last defined is at the top of the
stack... Hence "call-next-method".

I'm not sure but, it seems like so long as the parameters are discernable
and discernibly different that lisp can "figure out" which one to call? I'm
not quite sure why it's so different? Oh well, I do hope to grasp it.

Anyway thanks again.


Pascal J. Bourguignon

unread,
Jul 31, 2009, 12:43:31 PM7/31/09
to
"David Greene" <Da...@NoWhere.com> writes:
> Sorry guys... I didn't mean to be obtuse... I swapped out the
> initialize-instance :after and added (call-next-method) as the first line in
> initialize-instance and all runs as expected. It's just that call NEXT
> method seems so weird? In my head there is no NEXT method only previously
> defined methods in x number of superclasses.
>
> If I may suggest for CLOS newbie's from other OOP languages... All the other
> stuff for me is yet to be discovered. In order to last long enough to
> discover it I need to be able to write in a fashion at least a little
> familiar with what I am used to. I don't want or mean to be ungrateful,
> thank you both very much, but jumping on there is no this pointer is really
> hard to grasp. Or that methods don't belong to classes it true but, not
> terribly helpful for a newbie. I know that it's somewhat dangerous to make a
> newbie think something that isn't quite accurate is problematic for the
> newbie down the road. On the other hand if the newbie gets so confused as to
> give up the attempt it serves no one's interest either.
> [...]

And besides, you can implement in Common Lisp your own object system,
either by defining new meta-classes in CLOS, or by building it totally
on the side.

There is for example the KR object system ("Knowledge
Representation"), which is used by the Garnet GUI toolkit, which is
prototype based (a little like javascript object system), and features
an automatic update of the fields values upon change of their
dependant expression (like Cells http://common-lisp.net/project/cells/
which implements the feature for CLOS).

Actually, you could define a simple single-inheriting, methods
attached to the class object system in less than a page of Common Lisp
code entirely independant of CLOS.

But once you'll have learned enough to be able to do so, you won't
want to use anything else than CLOS! :-)

--
__Pascal Bourguignon__

Rainer Joswig

unread,
Jul 31, 2009, 1:10:42 PM7/31/09
to
On 31 Jul., 18:42, "David Greene" <D...@NoWhere.com> wrote:
> Thanks-
>
> It almost seems like we are talking about compiled vs uncompiled stuff? I
> don't know if I can say what I want coherently. I have clearly missed the
> mark in my previous posts about OOP.
>
> In c# there are multi-functions as well:
>
> assume we are lexically within some class:
>
> foo( int x ) { /* do something with the int */ }
> foo( string x ) { /* do something with a string */ }
>
> I can now call classx.foo( 1 ); and the integer function will be called. On
> the other hand I can also call classx.foo( "hello" ); and classx will do
> something with the string.

It looks similar, but it really is different - see below.


>
> Now the c# compiler "figures out" which function to call, I use this
> "feature" all the time. I think you are saying that lisp has the same
> "feature" because the list of "possible functions" is a list of functions
> ordered in a "push stack fashion" or last defined is at the top of the
> stack... Hence "call-next-method".
>
> I'm not sure but, it seems like so long as the parameters are discernable
> and discernibly different that lisp can "figure out" which one to call? I'm
> not quite sure why it's so different? Oh well, I do hope to grasp it.

C# did not support multiple dispatch last I looked. It has basically
the same restriction as C++.

The reason is that the COMPILER will at compile time determine the
type of the other parameters and select the method for that TYPE. It
does not do runtime dispatch. C# dispatches at runtime only looking at
the first parameter.

From http://stackoverflow.com/questions/479923/is-c-a-single-dispatch-or-multiple-dispatch-language

int CaptureSpaceShip(IRebelAllianceShip ship) {}
int CaptureSpaceShip(XWing ship) {}

void Main() {
IRebelAllianceShip theShip = new XWing();
CaptureSpaceShip(theShip);
}

C# calls the first method, not the second how it 'should'.

Common Lisp dispatches at runtime over all (1..n) arguments.

>
> Anyway thanks again.

Alberto Riva

unread,
Jul 31, 2009, 3:14:08 PM7/31/09
to
David Greene wrote:
> "Alberto Riva" <ar...@nospam.ufl.edu> wrote:

>> David Greene wrote:
>>> I'm also not using init-form stuff on the slots because I don't want to.
>>> I would prefer to use initialize-instance and do what I want in that
>>> method.
>> Could you please explain this? Any particular reason why don't you want to
>> use initforms?
>
> Habit mostly... and even in c# there are ways of running "macros" or telling
> the compiler to insert a bunch of stuff that you can't really see the actual
> code the compiler is compiling. I prefer to be as explicit as possible in
> the lexical writing of my code so I don't have to figure out what code the
> compiler is actually compiling.

There's nothing mthreatening or mysterious about initforms: they simply
specify the value you want a slot to have when you create a new instance
of an object, unless you explicitly provide a different one. For example:


(defclass c1 ()
((slot1 :initform 0 :initarg :slot1 :accessor slot1)))

(make-instance 'c1) => slot1 has the value 0

(make-instance 'c1 :slot1 10) => slot1 has the value 10


That's it... it's true that defclass is a macro, but this has
essentially nothing to do with how initforms work. You should think of
the initform as part of the definition of your class, just as its name,
its slots names, etc. In the example above the initform was a constant,
but it could also be an expression that is computed at runtime, and it
would "just work" all the same.

Some people would say that this is an example of the psychological scars
that one suffers by being exposed to certain *other* languages, with
their arbitrary constraints and limitations and countless ways of
screwing you through contorted syntax and semantics or absurd
complexity: you [*] develop an instinctive defense mechanism by which
you try to stick to what you already know, since you know that by doing
it you won't suffer *too much*, and you're so afraid of venturing
outside that path because of the memory of the pain you felt whenever
you tried to in the past, that you lose the ability to recognize that
there are languages that are designed to *help* the programmer, and that
can be used with the expectation that they will provide you with the
right tool for the job and that it will work, rather than the
expectation that you will have to fight with them to get them to do what
you want.

[*] It's a generic "you", I'm not referring to *you* in particular, you
seem to be putting in the necessary effort to grasp how these things work...

> I am aware that defclass is a macro as is
> defmethod and a wide range of "calls" made in lisp.

I'm not sure I understand this sentence... are you saying that a lot of
Lisp operators are actually implemented as macros?

> It is for this reason, at this point, that I want to eliminate as much as
> possible the "stuff" that the macro injects into my program.

It's not the macro that injects it, it's stuff that you wrote... the
macro just makes it easier to write it, and makes sure it runs at the
right time.

> As I become more experienced I may well be comfortable/knowledgeable enough
> to use the various "slot switches" to my benefit.

There's not too many of them in the end:

:initform (default value of a slot that is not otherwise initialized)

:initarg (keyword argument used to initialize the slot in a call to
MAKE-INSTANCE, see example above)

:accessor (function to read/write slot value; you can also define the
:reader and :writer functions separately, but normally there's no need
to, accessors are just fine)

:documentation (a string that explains what the slot is for)

(plus a couple of others that you can live without for now). All of them
are optional, anyway, so you can start using them gradually... :)

> If I understand the CALL-NEXT-METHOD "stuff" it REQUIRES :before and :after
> stuff on the function in question.

No... where did you get this idea?

> Anyway usually there is some way to "cast" the this pointer to a pointer
> that can be used to explicitly call methods of the "base" class.

"cast" and "pointer" are terms that actually have no meaning in Lisp
(actually, they do, but not the meaning you think they have). As has
been mentioned several times before, the behavior you want is actually
more complex than the behavior you think you want, but luckily
CALL-NEXT-METHOD is there to make it happen correctly.

Alberto

Rainer Joswig

unread,
Jul 31, 2009, 8:01:08 PM7/31/09
to
In article <87ws5od...@galatea.local>,

:-)

I've played around a bit...

Given the following classes and methods:

(defclass thing () ())
(defclass vehicle (thing) ())
(defclass ship (vehicle) ())
(defclass boat (vehicle) ())
(defclass island (thing) ())

(defgeneric collide (object1 object2))

(defmethod collide ((o1 thing) (o2 thing)))
(defmethod collide :after ((o1 vehicle) (o2 vehicle)))
(defmethod collide ((o1 ship) (o2 boat)))
(defmethod collide :before ((o1 ship) (o2 boat)))
(defmethod collide :after ((o1 ship) (o2 boat)))
(defmethod collide :around ((o1 ship) (o2 boat)))
(defmethod collide ((o1 ship) (o2 island)))
(defmethod collide :after ((o1 ship) (o2 island)))
(defmethod collide ((o1 boat) (o2 island)))
(defmethod collide :around ((o1 boat) (o2 island)))


We get the following overview for the call

(collide (make-instance 'ship) (make-instance 'boat))


CL-USER 28 > (show-clos-gf #'collide (list (make-instance 'ship) (make-instance 'boat)))

(COLLIDE #<SHIP 200BFD7F> #<BOAT 200BFD6B>)


We get the following method ordering:

Method | Qualifier | OBJECT1 | OBJECT2 | Applicable
--------+-----------+---------+---------+-----------
COLLIDE | :AROUND | SHIP | BOAT | 1
COLLIDE | :BEFORE | SHIP | BOAT | Yes
COLLIDE | | SHIP | BOAT | 2
COLLIDE | | THING | THING | 3
COLLIDE | :AFTER | SHIP | BOAT | Yes
COLLIDE | :AFTER | VEHICLE | VEHICLE | Yes
COLLIDE | | SHIP | ISLAND | No
COLLIDE | :AFTER | SHIP | ISLAND | No
COLLIDE | | BOAT | ISLAND | No
COLLIDE | :AROUND | BOAT | ISLAND | No


The effective method form:

(CALL-METHOD
#<STANDARD-METHOD COLLIDE (:AROUND) (SHIP BOAT) 218E18AF>
((MAKE-METHOD
(PROGN
(CALL-METHOD #<STANDARD-METHOD COLLIDE (:BEFORE) (SHIP BOAT) 218AFC5B> NIL)
(MULTIPLE-VALUE-PROG1
(CALL-METHOD #<STANDARD-METHOD COLLIDE NIL (SHIP BOAT) 21884743> (#<STANDARD-METHOD COLLIDE NIL (THING THING) 2188C2AB>))
(CALL-METHOD #<STANDARD-METHOD COLLIDE (:AFTER) (VEHICLE VEHICLE) 21888F53> NIL)
(CALL-METHOD #<STANDARD-METHOD COLLIDE (:AFTER) (SHIP BOAT) 218AE047> NIL))))))


Here: First the around method gets called. Other methods are only called if the around method uses CALL-NEXT-METHOD.
If it uses CALL-NEXT-METHOD, then first the before method is called, then the next primary method and then the
after methods.

--
http://lispm.dyndns.org/

con...@black.gateway.2wire.net

unread,
Aug 1, 2009, 9:33:37 AM8/1/09
to
Rainer Joswig <jos...@lisp.de> writes:

> CL-USER 28 > (show-clos-gf #'collide (list (make-instance 'ship)
> (make-instance 'boat)))

Is this function available, looks pretty handy?

Thanks.

Tim Bradshaw

unread,
Aug 1, 2009, 10:33:37 AM8/1/09
to
On 2009-07-31 13:54:53 +0100, "David Greene" <Da...@NoWhere.com> said:

> I don't know how to reply to this. There is NOTHING you present that can't
> be done in other OO languages.

That's a very dangerous statement. It's obviously true in the sense
that all these languages are equivalent. But then you have to add all
sorts of languages you probably would not want to add which are also
equivalent (say, FORTRAN 77).

The issue is how the language encourages you to think and what it makes
easy & hard, not what it can do. And Rainer is right that, in this
sense, CLOS is very different than most "modern" OO languages. The
branch of the OOP tree on which CLOS sits diverged a long time ago from
most other langauages. I think you could argue it diverged either just
after, or possibly just *before* SmallTalk. If most other OO languages
are kinds of mammal, CLOS is a kind of bird or something like that. I
think there are other languages related to CLOS, but not very many
(maybe Dylan is quite close).

So, Rainer is right, you really do need to read a bunch about CLOS and
understand how it thinks about the world. This is not helped because
(to push my species analogy really too far) CLOS belongs to a really
little-known family of species, and there is not the huge literature
around it that exists around the mammal languages. Worse, much of the
literature around the mammal languages assumes that *there are no
non-mammal animals*, and thus, if it's not a mammal, it's not an animal
at all.

For a start:

> I understand what you mean but, it still fails to address the question at
> point here in this thread... How can the "base"/"immediate superclass" be
> addressed explicitly in CLOS.

*which* superclass? And the superclass of *which* argument to the method?

Tim Bradshaw

unread,
Aug 1, 2009, 10:35:23 AM8/1/09
to
On 2009-07-31 14:13:06 +0100, p...@informatimago.com (Pascal J.
Bourguignon) said:

> In the case of CLOS, the generic functions implement a standard
> algorithm, used for all methods, to determine in which order the
> methods of the superclasses are called by call-next-method, depending
> on the order of the class precedence list (depending on the arguments
> of the generic function, and the order in which superclasses are
> listed in the defclass form).

But of course, you can implement your own algorithm if you like and
tell a GF to use that. So you can't even assume that you can
second-guess the algorithm and "know" what the appropriate superclass
is.

Tim Bradshaw

unread,
Aug 1, 2009, 10:39:55 AM8/1/09
to
On 2009-07-31 15:56:23 +0100, "David Greene" <Da...@NoWhere.com> said:

> If I may suggest for CLOS newbie's from other OOP languages... All the other
> stuff for me is yet to be discovered. In order to last long enough to
> discover it I need to be able to write in a fashion at least a little
> familiar with what I am used to.

I think that's the problem with moving to CLOS. What you're saying is
a bit like "in order to last long enough to learn structured
programming I need to keep writing my programs with GO TO for a while,
and why won't this irritating Pascal language just let me do that".
You can see how that's really a silly statement: structured programming
is *about* not using GO TO, in the same way that CLOS is *about*
methods not belonging to classes &c &c. There is no easy transition,
it's a whole new world. That's probably bad news for CLOS, but it is,
unfortunately, true.

0 new messages