From: Benjamin Teuber
Subject: Simple CLOS-Example needed
Date: 
Message-ID: <e73fpc$d5n$1@kohl.informatik.uni-bremen.de>
Hi,

I'll have to hold an interactive presentation at a seminar called 
"Aspects of Object-Oriented Languages". "Interactive" means I will 
present an unfinished or bad program which the others have to rewrite 
and finish together.

Of course, I chose CLOS as my topic, and now I'm pondering on which 
aspects of CLOS to focus and what kind of application to give them.

I guess that advanced MOP-stuff could be too difficult for students that 
never saw any Lisp (besides little Scheme-functions..), so my first idea 
would be to focus on the generic-function-approach and multimethods as 
one advantage of this view.
As an example, I could think of a simple math library with vectors and 
matrices and a few overloaded operators.

This is what I've got until now, but I'm not too satisfied with it and 
thought that maybe you could find some better examples or aspects of 
CLOS I can integrate without asking too much of them.

Any suggestions welcome,

Ben

From: Pedro Kröger
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150634785.134001.268120@p79g2000cwp.googlegroups.com>
Benjamin Teuber wrote:
> This is what I've got until now, but I'm not too satisfied with it and
> thought that maybe you could find some better examples or aspects of
> CLOS I can integrate without asking too much of them.

to me it's difficult to find good *and* simple examples for things like
these. anyway, you may want to watch Pascal's presentations about CLOS
for inspiration:

http://prog.vub.ac.be/events/2005/BADL/DLD/dld.html

Pedro Kroger
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <UNdlg.170$bc4.41@fe10.lga>
Pedro Kr�ger wrote:
> Benjamin Teuber wrote:
> 
>>This is what I've got until now, but I'm not too satisfied with it and
>>thought that maybe you could find some better examples or aspects of
>>CLOS I can integrate without asking too much of them.
> 
> 
> to me it's difficult to find good *and* simple examples for things like
> these.

Nonsense! The only hard part (OK) is making them realistic. We refactor 
and repair real programs all day long using CLOS and GFs, but then 
someone asks for an example and all of a sudden we start generating 
Fibonacci numbers. (Guilty.)

> anyway, you may want to watch Pascal's presentations about CLOS
> for inspiration:
> 
> http://prog.vub.ac.be/events/2005/BADL/DLD/dld.html

Omigod. The man works in academia, could not teach to save his life.

:)

kenny

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150653161.783344.269490@y41g2000cwy.googlegroups.com>
Benjamin Teuber wrote:
> Hi,
>
> I'll have to hold an interactive presentation at a seminar called
> "Aspects of Object-Oriented Languages". "Interactive" means I will
> present an unfinished or bad program which the others have to rewrite
> and finish together.
>
> Of course, I chose CLOS as my topic, and now I'm pondering on which
> aspects of CLOS to focus and what kind of application to give them.
>
> I guess that advanced MOP-stuff could be too difficult for students that
> never saw any Lisp (besides little Scheme-functions..), so my first idea
> would be to focus on the generic-function-approach and multimethods as
> one advantage of this view.
> As an example, I could think of a simple math library with vectors and
> matrices and a few overloaded operators.
>
> This is what I've got until now, but I'm not too satisfied with it and
> thought that maybe you could find some better examples or aspects of
> CLOS I can integrate without asking too much of them.
>
> Any suggestions welcome,
>
> Ben

I think the canonical example is showing how 2D shapes (square,
triangle, etc.) can be manipulated, rotated, areas determined, whatnot.

Personally, I would be most interested in seeing how to iterate through
each slot without having to know the slot names a priori.

Lou Vanek
From: Pascal Bourguignon
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <87y7vuqiqs.fsf@thalassa.informatimago.com>
"vanekl" <·····@acd.net> writes:
> Personally, I would be most interested in seeing how to iterate through
> each slot without having to know the slot names a priori.

[211]> (asdf:oos 'asdf:load-op :closer-mop)
...
[212]> (defclass c1 () (a b))
#1=#<STANDARD-CLASS C1>
[213]> (defclass c2 (c1) (d e f))
#1=#<STANDARD-CLASS C2>
[214]> (closer-mop:compute-slots (find-class 'c2))
(#<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION A #x2052E666>
 #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION B #x2052E6A6>
 #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION D #x2052E6E6>
 #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION E #x2052E726>
 #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION F #x2052E766>)

[217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
         (print (closer-mop:slot-definition-name slot)))

A 
B 
D 
E 
F 
NIL

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

ATTENTION: Despite any other listing of product contents found
herein, the consumer is advised that, in actuality, this product
consists of 99.9999999999% empty space.
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150674846.621110.39580@c74g2000cwc.googlegroups.com>
Pascal Bourguignon wrote:
> "vanekl" <·····@acd.net> writes:
> > Personally, I would be most interested in seeing how to iterate through
> > each slot without having to know the slot names a priori.
>
> [211]> (asdf:oos 'asdf:load-op :closer-mop)
> ...
> [212]> (defclass c1 () (a b))
> #1=#<STANDARD-CLASS C1>
> [213]> (defclass c2 (c1) (d e f))
> #1=#<STANDARD-CLASS C2>
> [214]> (closer-mop:compute-slots (find-class 'c2))
> (#<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION A #x2052E666>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION B #x2052E6A6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION D #x2052E6E6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION E #x2052E726>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION F #x2052E766>)
>
> [217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
>          (print (closer-mop:slot-definition-name slot)))
>
> A
> B
> D
> E
> F
> NIL
>
> --
> __Pascal Bourguignon__                     http://www.informatimago.com/

Cool. This even works on Clisp. I knew there was a simple way of doing
this and have been looking for over a week. Since being able to do
reflection is so powerful and yet scarce in most programming languages,
I find things like this much more interesting than polymorphism,
encapsulation, inheritance, and other OO constructs -- except for
message passing. Message passing is powerful, but I don't think CL uses
it. That's one thing I miss from using Ruby. Method_missing allowed you
to catch problems at runtime and adjust (or even eval a new method).
Off topic.

Anyway, thanks,

-lv
From: Pascal Bourguignon
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <87d5d6ro43.fsf@thalassa.informatimago.com>
"vanekl" <·····@acd.net> writes:

> Pascal Bourguignon wrote:
>> "vanekl" <·····@acd.net> writes:
>> > Personally, I would be most interested in seeing how to iterate through
>> > each slot without having to know the slot names a priori.
>> [217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
>>          (print (closer-mop:slot-definition-name slot)))
>> A
>> B
>> D
>> E
>> F
>> NIL
> Cool. This even works on Clisp.

Didn't you know that clisp has the best MOP support of all CL implementations?
The closer-mop adaptation layer for clisp is the smallest:

[···@thalassa closer-mop]$ for d in allegro/ clisp/ ecl/ lispworks/ mcl/ pcl/ ;\
do printf '%20s %8d\n' $d $(wc -c $d/*.lisp|tail -1|awk '{print $1}') ; done
            allegro/    12866
              clisp/     6693
                ecl/    17601
          lispworks/    30675
                mcl/    12341        (mcl & openmcl)
                pcl/    16459        (cmucl & sbcl)



I wonder why people don't believe clisp is the best free implementation...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"A TRUE Klingon warrior does not comment his code!"
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150677143.904282.252510@g10g2000cwb.googlegroups.com>
Pascal Bourguignon wrote:
> "vanekl" <·····@acd.net> writes:
>
> > Pascal Bourguignon wrote:
> >> "vanekl" <·····@acd.net> writes:
> >> > Personally, I would be most interested in seeing how to iterate through
> >> > each slot without having to know the slot names a priori.
> >> [217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
> >>          (print (closer-mop:slot-definition-name slot)))
> >> A
> >> B
> >> D
> >> E
> >> F
> >> NIL
> > Cool. This even works on Clisp.
>
> Didn't you know that clisp has the best MOP support of all CL implementations?
> The closer-mop adaptation layer for clisp is the smallest:
>
> [···@thalassa closer-mop]$ for d in allegro/ clisp/ ecl/ lispworks/ mcl/ pcl/ ;\
> do printf '%20s %8d\n' $d $(wc -c $d/*.lisp|tail -1|awk '{print $1}') ; done
>             allegro/    12866
>               clisp/     6693
>                 ecl/    17601
>           lispworks/    30675
>                 mcl/    12341        (mcl & openmcl)
>                 pcl/    16459        (cmucl & sbcl)
>
>
>
> I wonder why people don't believe clisp is the best free implementation...

Oh, that's a simple one: it doesn't do threads, which makes web
programming much more exciting. Fix that one thing and Clisp would be
my friend.
-lv
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <Q7nlg.1242$PG4.38@fe12.lga>
Pascal Bourguignon wrote:
> "vanekl" <·····@acd.net> writes:
> 
>>Cool. This even works on Clisp.
> 
> 
> Didn't you know that clisp has the best MOP support of all CL implementations?
....
> I wonder why people don't believe clisp is the best free implementation...
> 

I think the problem is the same reputational persistence dogging Lisp 
even now, and Tcl/Tk based on a recent exchange here on c.l.l: until 
relatively recently CLisp was deficient in MOP support and FFI. I refuse 
to guess at dates since I have reached an age where years go by like 
fenceposts, but hell, Lisp has not been slow for thirty years so it does 
not matter: reputations are indelible.

I get a huge kick out of CLisp doing so well when it finally cured those 
issues. I remember going nuts trying to port Cells-Gtk from its awesome 
new FFI (the maintainers love it when I call it new) to UFFI.

If it had an IDE I would be switching to that instead of Lispworks.

kenny

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Pascal Bourguignon
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <874pyhsui1.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:

> Pascal Bourguignon wrote:
>> "vanekl" <·····@acd.net> writes:
>> 
>>>Cool. This even works on Clisp.
>> Didn't you know that clisp has the best MOP support of all CL
>> implementations?
> ....
>> I wonder why people don't believe clisp is the best free implementation...
>> 
>
> I think the problem is the same reputational persistence dogging Lisp
> even now, and Tcl/Tk based on a recent exchange here on c.l.l: until
> relatively recently CLisp was deficient in MOP support and FFI. 

Clisp deficient in FFI!  Better reading that than be blind...

> I
> refuse to guess at dates since I have reached an age where years go by
> like fenceposts, but hell, Lisp has not been slow for thirty years so
> it does not matter: reputations are indelible.
>
> I get a huge kick out of CLisp doing so well when it finally cured
> those issues. I remember going nuts trying to port Cells-Gtk from its
> awesome new FFI (the maintainers love it when I call it new) to UFFI.

The point is that clisp FFI is so much better (higher level) than the
lowest common denominator, that indeed UFFI that targets that low
level had difficulties to make use of clisp FFI.


> If it had an IDE I would be switching to that instead of Lispworks.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Joe Marshall
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150732081.363910.39150@f6g2000cwb.googlegroups.com>
vanekl wrote:
> Message passing is powerful, but I don't think CL uses
> it. That's one thing I miss from using Ruby. Method_missing allowed you
> to catch problems at runtime and adjust (or even eval a new method).

Message passing is semantically equivalent to function calling.  I
think CL has that.
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150735586.477243.96750@u72g2000cwu.googlegroups.com>
Joe Marshall wrote:
> vanekl wrote:
> > Message passing is powerful, but I don't think CL uses
> > it. That's one thing I miss from using Ruby. Method_missing allowed you
> > to catch problems at runtime and adjust (or even eval a new method).
>
> Message passing is semantically equivalent to function calling.  I
> think CL has that.

So are you saying that it's possible to call a method that doesn't
exist, catch the error, define the non-existent method, and then invoke
it, all at runtime?
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymid5d57xze.fsf@sevak.isi.edu>
"vanekl" <·····@acd.net> writes:

> Joe Marshall wrote:
> > vanekl wrote:
> > > Message passing is powerful, but I don't think CL uses
> > > it. That's one thing I miss from using Ruby. Method_missing allowed you
> > > to catch problems at runtime and adjust (or even eval a new method).
> >
> > Message passing is semantically equivalent to function calling.  I
> > think CL has that.
> 
> So are you saying that it's possible to call a method that doesn't
> exist, catch the error, define the non-existent method, and then invoke
> it, all at runtime?

Yes.

For example:

USER> (defgeneric foo (x))
#<STANDARD-GENERIC-FUNCTION FOO>
USER> (defmethod foo ((x FLOAT))
  (format t "~8,3F" x))

#<STANDARD-METHOD FOO (FLOAT)>
USER> (foo pi)
   3.142
NIL
USER> (foo 7)
Error: No methods applicable for generic function #<STANDARD-GENERIC-FUNCTION FOO> with args (7) of
       classes (FIXNUM)
  [condition type: PROGRAM-ERROR]

Restart actions (select using :continue):
 0: Try calling it again
 1: Return to Top Level (an "abort" restart)
 2: Abort #<PROCESS Initial Lisp Listener>
[1c] USER> (defmethod foo ((x INTEGER))
	     (format t "~8D" x))
#<STANDARD-METHOD FOO (INTEGER)>
[1c] USER> :continue
       7
NIL



-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150790595.351330.280430@u72g2000cwu.googlegroups.com>
Thomas A. Russ wrote:
> "vanekl" <·····@acd.net> writes:
>
> > Joe Marshall wrote:
> > > vanekl wrote:
> > > > Message passing is powerful, but I don't think CL uses
> > > > it. That's one thing I miss from using Ruby. Method_missing allowed you
> > > > to catch problems at runtime and adjust (or even eval a new method).
> > >
> > > Message passing is semantically equivalent to function calling.  I
> > > think CL has that.
> >
> > So are you saying that it's possible to call a method that doesn't
> > exist, catch the error, define the non-existent method, and then invoke
> > it, all at runtime?
>
> Yes.
>
> For example:
>
> USER> (defgeneric foo (x))
> #<STANDARD-GENERIC-FUNCTION FOO>
> USER> (defmethod foo ((x FLOAT))
>   (format t "~8,3F" x))
>
> #<STANDARD-METHOD FOO (FLOAT)>
> USER> (foo pi)
>    3.142
> NIL
> USER> (foo 7)
> Error: No methods applicable for generic function #<STANDARD-GENERIC-FUNCTION FOO> with args (7) of
>        classes (FIXNUM)
>   [condition type: PROGRAM-ERROR]
>
> Restart actions (select using :continue):
>  0: Try calling it again
>  1: Return to Top Level (an "abort" restart)
>  2: Abort #<PROCESS Initial Lisp Listener>
> [1c] USER> (defmethod foo ((x INTEGER))
> 	     (format t "~8D" x))
> #<STANDARD-METHOD FOO (INTEGER)>
> [1c] USER> :continue
>        7
> NIL
>
>

This is not exactly equivelant to message passing based language.

When dealing with unknown dynamic message like this, there are two
disadvantages of generic-function approach.


First: you have to know before hand the name of "unknown" message.

For example, when querying a database return rows, I want each column
in a row to be accessible with:

(column-name row)

In Ruby, I can implement this as:

class RecordRow
  def initialize(datas)
    @datas = datas   # datas is hash table mapped from column name to
value.
  end
  def method_missing(method_name, *args)
     return @datas[method_name]
  end
end

And use it:

row.name    # get data in column "name" of the row.

You can not do this using generic function since you don't know all
possible column names for all SQL query. So you cannot do DEFGENERIC
before hand.

 *** Looking up the Hysperspce, however,  it seems that I can use
ENSURE-GENERIC-FUNCTION at initialization time of each record to
dynamically create generic functions for all column names. ***

But, there are still another disadvantages of generic function approach
that ENSURE-GENERIC-FUNCTION won't solve.

Second disadvantage: There can only be one generic function signature
in a package.

Suppose I uses ENSURE-GENERIC-FUNCTION in my library so that I can
conveniently access any column with function call style. Then later I
use another XML library that also allow me to access named subchild of
a node using function call style. The library designer of both library
must be careful to ensure generic function in their own package.
This package must be package that client package should not USE/IMPORT
symbols from but refers to it with full name to prevent name clash.
Or else the two generic function ROW:NAME and NODE:NAME will have
symbol name clash in the client code.


I suppose both problem is not a big deal, one has to be careful when
designing a library anyway. But then you have to jump through hoops to
correctly implement message passing behavior, so may be you are "Red
spunning" :-D


-----

Moreover, I would like to note that function call and message passing
are not equivelant, at least between Common Lisp and Ruby.

The most obvious different is that (Generic) function has package and
signature, message does not. This different can be
advantage/disadvantage to each approach depending on the situation.

 (in-package :p1) (defun foo () ...)
 (in-package :p2) (defun foo () ...)           ;; p2 CANNOT use p1.

(in-package :cl-user)               ;; cannot use p1 and p2 at the same
time.
(mapcar #'foo                         ;; This won't work
  (list  (make-instance 'p1:x)    ;; But we can be sure to get the
right interface contract.
         (make-instance 'p2:x)))


module P1
  class X;  def foo() end ; end
end
module P2
  class X;  def foo() end ; end
end

[P1::X.new,  P2::X.new].map{|x|  x.send :foo }   # this will work



A generic function name is tied to a package, and its specified
signature. So function name carries interface with it.
A message has no package information there is no method signature tied
to it.
Message is resolved to a contract/interface by sending it to the
reciever. While a generic function name, unless shadow, will always
refer to one contract/interface.

Message based language makes sandboxing, creating DSL easier than
function-based language.

Because no matter whatever package you are in, message still resolve
correctly with respect to the receiver of the message.
But in function-based system, you have to refer to the correct package.

For example to build XML with CL-WHO from package that doesnot
use/import CL-WHO symbol

(cl-who:with-html-output (...)
   (:html (:body (STR "this won't work, use CL-WHO:STR instead"))))

With message based, one could do:

Xml.out {
  html {
     body {
        str "This work"
     }
  }
}


Not to say message based is better, but that each has their own use and
advantages.

> 
> -- 
> Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymizmg77gwu.fsf@sevak.isi.edu>
"Pisin Bootvong" <··········@gmail.com> writes:

> Thomas A. Russ wrote:
> > "vanekl" <·····@acd.net> writes:
> >
> > > Joe Marshall wrote:
> > > > vanekl wrote:
> > > > > Message passing is powerful, but I don't think CL uses
> > > > > it. That's one thing I miss from using Ruby. Method_missing allowed you
> > > > > to catch problems at runtime and adjust (or even eval a new method).
> > > >
> > > > Message passing is semantically equivalent to function calling.  I
> > > > think CL has that.
> > >
> > > So are you saying that it's possible to call a method that doesn't
> > > exist, catch the error, define the non-existent method, and then invoke
> > > it, all at runtime?
> >
> > Yes.
> >
> > For example:
... snip
> >
> 
> This is not exactly equivelant to message passing based language.
> 
> When dealing with unknown dynamic message like this, there are two
> disadvantages of generic-function approach.
> 
> 
> First: you have to know before hand the name of "unknown" message.
> 
> For example, when querying a database return rows, I want each column
> in a row to be accessible with:
> 
> (column-name row)
> 
> In Ruby, I can implement this as:
> 
> class RecordRow
>   def initialize(datas)
>     @datas = datas   # datas is hash table mapped from column name to
> value.
>   end
>   def method_missing(method_name, *args)
>      return @datas[method_name]
>   end
> end
> 
> And use it:
> 
> row.name    # get data in column "name" of the row.

Sorry, I don't have the time right now to look for the CL equivalent.
Perhaps someone else does?


> You can not do this using generic function since you don't know all
> possible column names for all SQL query. So you cannot do DEFGENERIC
> before hand.

True.  But you can do DEFGENERIC or perhaps better,
ENSURE-GENERIC-FUNCTION at the same time you do DEFMETHOD.  Actually,
you can dispense with the DEFGENERIC entirely and just use DEFMETHOD,
since Common Lisp will provide a DEFGENERIC.


>  *** Looking up the Hysperspce, however,  it seems that I can use
> ENSURE-GENERIC-FUNCTION at initialization time of each record to
> dynamically create generic functions for all column names. ***

Oh, I see you found this.

> But, there are still another disadvantages of generic function approach
> that ENSURE-GENERIC-FUNCTION won't solve.
> 
> Second disadvantage: There can only be one generic function signature
> in a package.

Well, yes.  But that is generally seen as an advantage.  Because a
generic function is supposed to encapsulate a particular semantic
operation.  It would be confusing, to say the least, if the basic
meaning of the action differed depending on which object is an
argument.

I would think that in message passing, you wouldn't want to accidentally
use the same message to mean two or more different things, would you?

> Suppose I uses ENSURE-GENERIC-FUNCTION in my library so that I can
> conveniently access any column with function call style. Then later I
> use another XML library that also allow me to access named subchild of
> a node using function call style. The library designer of both library
> must be careful to ensure generic function in their own package.
> This package must be package that client package should not USE/IMPORT
> symbols from but refers to it with full name to prevent name clash.
> Or else the two generic function ROW:NAME and NODE:NAME will have
> symbol name clash in the client code.

Well, I would think that a message-passing system would have similar
problems, wouldn't it?  What if you have two libraries that both
implement the same message on the same object?  You would have the same
name clash.

> -----
...snip CL.
> 
> module P1
>   class X;  def foo() end ; end
> end
> module P2
>   class X;  def foo() end ; end
> end
> 
> [P1::X.new,  P2::X.new].map{|x|  x.send :foo }   # this will work

But would you really want it to?

This isn't sending the SAME message to each object, it is sending
different messages which just happen to have the same name.

Since the messages are really different, you could just as easily have
given them different names, since what you want is to actually have
different things happen.  It seems that relying on such naming
coincidences between unrelated functionality is a Bad Idea(TM).  Why
should anyone expect that modules P1 and P2 both contain separate, but
different implementations that share a name?  Why would you want to use
a mapping construct to do what is effectively
   x1.send  :foo
   x2.send  :bar
since the messages aren't really the same.  Or perhaps they are the
same, in which case, you really do have the equivalent of a single
generic function which is available in both languages.

Note that if these messages took different numbers of arguments, you
wouldn't be able to write a mapping operation.


Perhaps Ruby doesn't allow this, but can you define a class Y that
inherits from both P1::X and P2::X?  Which definition does it execute if
it gets a :foo message?


> 
> 
> 
> A generic function name is tied to a package, and its specified
> signature. So function name carries interface with it.
> A message has no package information there is no method signature tied
> to it.
> Message is resolved to a contract/interface by sending it to the
> reciever. While a generic function name, unless shadow, will always
> refer to one contract/interface.
> 
> Message based language makes sandboxing, creating DSL easier than
> function-based language.
> 
> Because no matter whatever package you are in, message still resolve
> correctly with respect to the receiver of the message.
> But in function-based system, you have to refer to the correct package.
> 
> For example to build XML with CL-WHO from package that doesnot
> use/import CL-WHO symbol
> 
> (cl-who:with-html-output (...)
>    (:html (:body (STR "this won't work, use CL-WHO:STR instead"))))
> 
> With message based, one could do:
> 
> Xml.out {
>   html {
>      body {
>         str "This work"
>      }
>   }
> }
> 
> 
> Not to say message based is better, but that each has their own use and
> advantages.
> 
> > 
> > -- 
> > Thomas A. Russ,  USC/Information Sciences Institute
> 

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150840858.510425.131680@c74g2000cwc.googlegroups.com>
Thomas A. Russ wrote:

> "Pisin Bootvong" <··········@gmail.com> writes:
> > Second disadvantage: There can only be one generic function signature
> > in a package.
>
> Well, yes.  But that is generally seen as an advantage.  Because a
> generic function is supposed to encapsulate a particular semantic
> operation.  It would be confusing, to say the least, if the basic
> meaning of the action differed depending on which object is an
> argument.

I consider being able to send a variable number or type of function
argument more helpful than confusing. As well as polymorphism. To each
his own, I guess.


> > -----
> ...snip CL.
> >
> > module P1
> >   class X;  def foo() end ; end
> > end
> > module P2
> >   class X;  def foo() end ; end
> > end
> >
> > [P1::X.new,  P2::X.new].map{|x|  x.send :foo }   # this will work
>
> But would you really want it to?

Why not? CAD programs need to tell every object on the screen to redraw
themselves. This makes it easy.



> This isn't sending the SAME message to each object, it is sending
> different messages which just happen to have the same name.

Not necessarily. See example above.


> Note that if these messages took different numbers of arguments, you
> wouldn't be able to write a mapping operation.

Actually, you still could in Ruby. Ruby allows for functions which have
variable number of arguments, and spurious arguments may be ignored
(w/o warnings being issued or having to specify a declare/ignore).


> Perhaps Ruby doesn't allow this, but can you define a class Y that
> inherits from both P1::X and P2::X?  Which definition does it execute if
> it gets a :foo message?

Ruby doesn't support multiple inheritence but it has mixins. And all
objects inherit from the same root class. In practice the namespaces
have never clashed for me in this manner so I don't know what the
behavior is because it's really not much of an issue.

Lou Vanek
--
Robert Heinlein: "If you are ever in an argument with your wife and
discover that you are in the right, apologize immediately."
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymiveqv773i.fsf@sevak.isi.edu>
"vanekl" <·····@acd.net> writes:

> > ...snip CL.
> > >
> > > module P1
> > >   class X;  def foo() end ; end
> > > end
> > > module P2
> > >   class X;  def foo() end ; end
> > > end
> > >
> > > [P1::X.new,  P2::X.new].map{|x|  x.send :foo }   # this will work
> >
> > But would you really want it to?
> 
> Why not? CAD programs need to tell every object on the screen to redraw
> themselves. This makes it easy.

Correct.  But that would (in the lisp world) then be a SINGLE generic
function, named by the same symbol (package + symbol name), and not two
different symbols.

That is the entire point.  You wouldn't want to map a single DRAW
function across display objects and playing card decks for solitaire
games.  You would want a way of knowing which of the different meanings
of DRAW you are actually getting, i.e.,  CARD:DRAW or GRAPHICS:DRAW.


> > This isn't sending the SAME message to each object, it is sending
> > different messages which just happen to have the same name.
> 
> Not necessarily. See example above.

I'm not sure I understand how that changes things.  Here you clearly
have two different objects named "X", which are clearly meant to be
distinct.  So it is intended that P1::X and P2::X not be the same
class.  So why should it be the case that P1::foo and P2::foo are the
same?  How is anybody to know?


> > Note that if these messages took different numbers of arguments, you
> > wouldn't be able to write a mapping operation.
> 
> Actually, you still could in Ruby. Ruby allows for functions which have
> variable number of arguments, and spurious arguments may be ignored
> (w/o warnings being issued or having to specify a declare/ignore).

But what if the arguments are important and not compatible?  Suppose in
the hypothetical DRAW case, the card-deck draw takes the number of cards
to draw and the GRAPHICS draw takes a particular graphics device.  How
in the world do you come up with a mapping function that applies the two
different types of DRAW to objects?  What sort of arguments would you
even try to pass?

> > Perhaps Ruby doesn't allow this, but can you define a class Y that
> > inherits from both P1::X and P2::X?  Which definition does it execute if
> > it gets a :foo message?
> 
> Ruby doesn't support multiple inheritence but it has mixins. And all
> objects inherit from the same root class. In practice the namespaces
> have never clashed for me in this manner so I don't know what the
> behavior is because it's really not much of an issue.

Well, if you never have such namespace clashes, it must be because of
careful (or lucky?) design to keep the namespaces separate.  But you get
exactly the same thing with CL generic functions, since you would have
the same function applied to all items.

I guess part of this may be related to when namespaces are resolved.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymir71j76qv.fsf@sevak.isi.edu>
"vanekl" <·····@acd.net> writes:

> Thomas A. Russ wrote:
> 
> > "Pisin Bootvong" <··········@gmail.com> writes:
> > > Second disadvantage: There can only be one generic function signature
> > > in a package.
> >
> > Well, yes.  But that is generally seen as an advantage.  Because a
> > generic function is supposed to encapsulate a particular semantic
> > operation.  It would be confusing, to say the least, if the basic
> > meaning of the action differed depending on which object is an
> > argument.
> 
> I consider being able to send a variable number or type of function
> argument more helpful than confusing. As well as polymorphism. To each
> his own, I guess.

Well, I have gone over to the CLOS view that you really want to have a
core set of arguments specified for the generic function as a whole, or
else you really do lose the benefits of method dispatch.

I mean, one of the key benefits is that you don't have to know exactly
which type of argument you have when you call the generic method (or
send a message).  That allows you to freely substitute more specific
object instances for more general ones (i.e., instances of subclasses)
and still have them work.  You can get (slightly) different behaviors
based on individual characteristics, but you would want the same general
class of behaviors.

If you have different numbers of arguments possible or required based on
the specific type, then you lose all of the benefits of polymorphism and
subtitutabilty.  If you have to know exactly which class the object
belongs to in order to figure out which arguments are allowed or
required, then you might as well give the functions different names,
since you don't have the interchangeability anymore.

Now, that said, it is possible in CL to provide ancilliary arguments
(generally keyword arguments) to generic functions, and it is possible
for the supported keyword arguments to differ from method to method.  I
have come to think this is a bad design practice, for the reasons I
outline above, but it is allowed.

I would prefer to have the set of arguments fixed for the generic
function, and have some possibly ignored if irrelevant, but I don't like
the idea of needing to know what argument type I have in order to figure
out exactly which set of arguments I can pass to the function.  If you
need to do that, what's the point of method dispatch?

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150860612.164567.87860@c74g2000cwc.googlegroups.com>
Thomas A. Russ wrote:
> "Pisin Bootvong" <··········@gmail.com> writes:
>

[snip]

>
> > But, there are still another disadvantages of generic function approach
> > that ENSURE-GENERIC-FUNCTION won't solve.
> >
> > Second disadvantage: There can only be one generic function signature
> > in a package.
>
> Well, yes.  But that is generally seen as an advantage.  Because a
> generic function is supposed to encapsulate a particular semantic
> operation.  It would be confusing, to say the least, if the basic
> meaning of the action differed depending on which object is an
> argument.
>

Reply below, last section.

> I would think that in message passing, you wouldn't want to accidentally
> use the same message to mean two or more different things, would you?
>
> > Suppose I uses ENSURE-GENERIC-FUNCTION in my library so that I can
> > conveniently access any column with function call style. Then later I
> > use another XML library that also allow me to access named subchild of
> > a node using function call style. The library designer of both library
> > must be careful to ensure generic function in their own package.
> > This package must be package that client package should not USE/IMPORT
> > symbols from but refers to it with full name to prevent name clash.
> > Or else the two generic function ROW:NAME and NODE:NAME will have
> > symbol name clash in the client code.
>
> Well, I would think that a message-passing system would have similar
> problems, wouldn't it?  What if you have two libraries that both
> implement the same message on the same object?  You would have the same
> name clash.
>

Yes, message passing system will have a problem when two libraries
implement same message name on the same object.

BUT, generic function system will have a problem when two libraries
implement same message name on the same **package**, not object.

[NOTE: Java allow method overloading, so in Java, if two method have
same name but different argument type, you will still be able to query
for correct method. But I guess you know how many LOC it takes to
dynamically send a single message in java :-D]

[snip]


As I have said here

> >
> >
> > A generic function name is tied to a package, and its specified
> > signature. So function name carries interface with it.
> > A message has no package information there is no method signature tied
> > to it.
> > Message is resolved to a contract/interface by sending it to the
> > reciever. While a generic function name, unless shadow, will always
> > refer to one contract/interface.
> >

Generic function is a semantic/contract/interface name; it is tied to a
package, not any object or class. So instead of calling:

 (name person)

You have to call:

 (person:name person)

But why can't message be resolved only by name and not its package?
It is because function is global. The look up mechanism of function is
in global namespace. Since you don't look up a method through object,
but rather through environment, you will need something to give scope
to what method will be invoke.

In case of message passing system, the fact that message only have name
is not a big trouble because the scope of message can be found easily
by its receiver.


Yes, it is true you can't know what

obj.send :foo

will invoke. But in dynamic language, its advantage may be debatable.

Deciding which is better between

(person:name person)
and
person.name

Is like deciding between static and dynamic type language

 void printName(Person p){
   String s = p.getName();
   printLn(s);
 }
and
 defun print_name(p)
   s = p.name
   puts s
 end

In one case, the contract/semantic is shown, more typechecking can be
done at compiled time.
But in the other case, the trust is put more on people, the code may
error on runtime for invalid code, but it might be more pleasant to
work with.

-----------------

Performance aside, it is possible to have Lisp with even more dynamic
mechanism than "multiple dispatch" -- where function don't have
package, only name, then what generic function/method is called is
based on runtime type of all values.
So calls to:

(load file)
(load system component)
(load image)

depending on values of arguments, calls correct version of

(sys:load file)
(app:load system component)
(image:load image)

Whether this is useful and convenient or a chaos, we will have to
experiment with. (NOTE: It can even be done at compile time is such
Lisp support type inferrence)

> 
> -- 
> Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymiejxi79pj.fsf@sevak.isi.edu>
"Pisin Bootvong" <··········@gmail.com> writes:
> 
> Yes, message passing system will have a problem when two libraries
> implement same message name on the same object.
> 
> BUT, generic function system will have a problem when two libraries
> implement same message name on the same **package**, not object.

Well, one should not write different libraries that use the same
package.  Each library with separate functionality should have its own
package.

Now there is a minor practical problem that there is no particular
naming convention for Common Lisp packages, so certain popular package
names do run the risk of collision:  "GRAPHICS", "SYSTEM", "REGEX".
There has been some suggestion of adopting the Java package naming
convention, but that has not yet been widely adopted.  It would probably
be a good idea, though.

> [NOTE: Java allow method overloading, so in Java, if two method have
> same name but different argument type, you will still be able to query
> for correct method. But I guess you know how many LOC it takes to
> dynamically send a single message in java :-D]

Actually, Java only allows static overloading of methods.  The only
dynamic dispatch done is based on the first argument.  In contrast, CLOS
does give you true dynamic multiple-dispatch.

> [snip]
> 
> 
> As I have said here
> 
> > >
> > >
> > > A generic function name is tied to a package, and its specified
> > > signature. So function name carries interface with it.
> > > A message has no package information there is no method signature tied
> > > to it.
> > > Message is resolved to a contract/interface by sending it to the
> > > reciever. While a generic function name, unless shadow, will always
> > > refer to one contract/interface.
> > >
> 
> Generic function is a semantic/contract/interface name; it is tied to a
> package, not any object or class. So instead of calling:
> 
>  (name person)
> 
> You have to call:
> 
>  (person:name person)
> 
> But why can't message be resolved only by name and not its package?

Methods are resolved only by name in Common Lisp.

Because in Common Lisp, symbols are used to name objects.  Symbols are
objects in their own right, and can be considered to always have a name
like "package:name".  It is only a convenient shortcut that the system
allows you to specify a particular namespace as the current one and
leave off the package for that namespace.

If you consider that the real name of any method or generic function
really is the composite name, then it makes no more sense to consider 
   "p1:foo" and "p2:foo" the same as it would be to consider the names
   "p1_foo" and "p2_foo" to be the same.
In fact, Emacs Lisp, which does not have a package system, fakes it by
using the colon in the name of its symbols.

Methods are resolved only by name in Common Lisp.  Just because there
are ways of getting to the individual subparts of that name doesn't mean
anything.

Reductio ad absurdum:
Why shouldn't we have messages that are resolved only by matching a
substring?   

> It is because function is global. The look up mechanism of function is
> in global namespace. Since you don't look up a method through object,
> but rather through environment, you will need something to give scope
> to what method will be invoke.

Correct.  But you can't have true multiple dispatch any other way,
because multiple dispatch means that methods CANNOT belong to any
particular object.  With multiple dispatch there is NO distinguished
object that you can choose which is used to look up function names.

That is the entire point of the GENERIC-FUNCTION architecture.  It is a
different object model.  I happen to feel (somewhat strongly, as you may
have guessed) that this model is superior to the currently dominant OO
model of tying methods to single classes.

The key point is that you need some way of determining which function or
method you will invoke.  In CLOS, methods are associated with generic
functions.  Just as you would find it absurd to say, why don't we match
classes by name (across modules) in order to find which method applies,
it is absurd in Common Lisp to suggest that one use just the name
component.

In Common Lisp, two symbols in different packages may coincidentally
have the same symbol name, but that doesn't make them any more similar
than two symbols with different names.  You don't want to build a
programming system that has unintended coincidences affect the behavior
of the system.  And that is exactly what you get when you allow
conflation of different objects because one of their attributes just
happens to be the same.

> In case of message passing system, the fact that message only have name
> is not a big trouble because the scope of message can be found easily
> by its receiver.

History lesson: Lisp (before Common Lisp) actually did use a
message-passing paradigm for its object system.  It was known as FLAVORS
and was quite prevalent on Lisp Machines.  Messages were keywords (and
thus a single symbol) and were passed using a SEND function, with syntax
somewhat like

     (send my-object :some-message arg1 arg2 ...)

Yet when it came time to standardize on an object system, CLOS, based on
generic functions and Common Loops was chosen instead.  It was felt that
there were many more advantages to the generic function approach than to
message passing.  And this decision was not taken in ignorance of the
message-passing paradigm.  There was a widely-distributed and fully
functional, implemented alternative that was explicitly rejected in
favor of generic functions.

> Yes, it is true you can't know what
> 
> obj.send :foo
> 
> will invoke. But in dynamic language, its advantage may be debatable.
> 
> Deciding which is better between
> 
> (person:name person)
> and
> person.name

But generic functions really come into their own when you have more than
just the single argument case:

  (multiply matrix-1 vector-5)
  (multiply matrix-1 5.0)

Versus having to embed the second level of dispatch in the Matrix
class.  Suppose we decide to add complex numbers?  Multiplication by
integers?  Rational numbers?  How do you do that, especially if you got
your matrix library from someone else and don't have the source?

> Is like deciding between static and dynamic type language
> 
>  void printName(Person p){
>    String s = p.getName();
>    printLn(s);
>  }
> and
>  defun print_name(p)
>    s = p.name
>    puts s
>  end
> 
> In one case, the contract/semantic is shown, more typechecking can be
> done at compiled time.
> But in the other case, the trust is put more on people, the code may
> error on runtime for invalid code, but it might be more pleasant to
> work with.

This is a completely separate issue.

> -----------------
> 
> Performance aside, it is possible to have Lisp with even more dynamic
> mechanism than "multiple dispatch" -- where function don't have
> package, only name, then what generic function/method is called is
> based on runtime type of all values.
> So calls to:
> 
> (load file)
> (load system component)
> (load image)
> 
> depending on values of arguments, calls correct version of
> 
> (sys:load file)
> (app:load system component)
> (image:load image)

And what, exactly, would be the precedence hierarchy among symbols in
packages?  Suppose one had

(defmethod image:load (name STRING) ...)
(defmethod sys:load (name STRING) ...)

and then one called

  (load "my-picture.gif")

which is the correct load to call?

So with this supposed extra flexibility, one would have to impose a new
rule, namely one which says if anyone used the same symbol-name for a
method anywhere, in any library which may be loaded with your code, they
better not have defined a method with the same name and dispatch
argument, even if they are trying to use a module system.

It seems that what you really want is to circumvent namespaces
entirely.  That seems a recipe for disaster.

> 
> Whether this is useful and convenient or a chaos, we will have to
> experiment with. (NOTE: It can even be done at compile time is such
> Lisp support type inferrence)

Chaos.  I don't think I need to experiment.  I'll just choose deductive
inference. 

-- 
Thomas A. Russ,  USC/Information Sciences Institute
Long live Aristole
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4ftgd6F1k09b5U1@individual.net>
Thomas A. Russ wrote:

> Reductio ad absurdum:
> Why shouldn't we have messages that are resolved only by matching a
> substring?   

ROTFL - that's what AspectJ does.

But nevermind... ;)


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1151131845.632634.139920@r2g2000cwb.googlegroups.com>
Thomas A. Russ wrote:
> "Pisin Bootvong" <··········@gmail.com> writes:
>
> And what, exactly, would be the precedence hierarchy among symbols in
> packages?  Suppose one had
>
> (defmethod image:load (name STRING) ...)
> (defmethod sys:load (name STRING) ...)
>
> and then one called
>
>   (load "my-picture.gif")
>
> which is the correct load to call?
>

I don't know.
 - Well, I only say a rough idea of what could be possible and haven't
even think of all the rule needed for a sound system.
 - Compiler could have issue warning in ambigous case, if it ever
happen for a single lisp image to contains two library with function of
exact signature. Most of the time though, even though function name is
identical, number of parameter and its first specialized argument will
be different -- library usually specialize method on its user-defined
classes.
 - In dynamic message based language like Ruby/Smalltalk, when you see
code "obj.foo", you cannot know whether this is "foo" from what class;
only unit test will show that. And yes in this imaginary language
people still use unit test.
 - I suppose if you want to be sure about what function you get, you
can always fallback to writing fully qualified (i.e., with package)
name. So you have ability to be flexible most of the time, But nothing
prevent you from specifying precise functions.

> So with this supposed extra flexibility, one would have to impose a new
> rule, namely one which says if anyone used the same symbol-name for a
> method anywhere, in any library which may be loaded with your code, they
> better not have defined a method with the same name and dispatch
> argument, even if they are trying to use a module system.
>
> It seems that what you really want is to circumvent namespaces
> entirely.  That seems a recipe for disaster.
>
> >
> > Whether this is useful and convenient or a chaos, we will have to
> > experiment with. (NOTE: It can even be done at compile time is such
> > Lisp support type inferrence)
>
> Chaos.  I don't think I need to experiment.  I'll just choose deductive
> inference.
>

By deductive inference, static typing is better
 - It forces you to pass correct argument in whole program at *compile
time*.
 - You don't know whether statement like: (FOO X) will trigger
NO-APPLICABLE-METHOD until runtime.
 - The compiler can optimize code better.
 - IDE can help you more with auto completion, etc.

Dynamic typing is viewed as chaos in theory until developer actually
experiment with it.
The usefulness of a feature can never be known until it is tried in
practice.

> --
> Thomas A. Russ,  USC/Information Sciences Institute
> Long live Aristole

Cheers,

Pisin Bootvong
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4fsc1oF1k9244U1@individual.net>
Pisin Bootvong wrote:
> Thomas A. Russ wrote:
>> Well, I would think that a message-passing system would have similar
>> problems, wouldn't it?  What if you have two libraries that both
>> implement the same message on the same object?  You would have the same
>> name clash.
> 
> Yes, message passing system will have a problem when two libraries
> implement same message name on the same object.
> 
> BUT, generic function system will have a problem when two libraries
> implement same message name on the same **package**, not object.
> 
[...]

> Generic function is a semantic/contract/interface name; it is tied to a
> package, not any object or class. So instead of calling:
> 
>  (name person)
> 
> You have to call:
> 
>  (person:name person)
> 
> But why can't message be resolved only by name and not its package?
> It is because function is global. The look up mechanism of function is
> in global namespace. Since you don't look up a method through object,
> but rather through environment, you will need something to give scope
> to what method will be invoke.
> 
> In case of message passing system, the fact that message only have name
> is not a big trouble because the scope of message can be found easily
> by its receiver.

...and yet in practice, the demand for module systems sooner or later 
comes up in languages which use only names to disambiguate messages, to 
be able to make finer distinctions. As soon as you have modules, you 
have to know more about the messages that you are sending apart from 
their names.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150885282.675654.202460@p79g2000cwp.googlegroups.com>
Pascal Costanza wrote:
> Pisin Bootvong wrote:
> > Thomas A. Russ wrote:
> >> Well, I would think that a message-passing system would have similar
> >> problems, wouldn't it?  What if you have two libraries that both
> >> implement the same message on the same object?  You would have the same
> >> name clash.
> >
> > Yes, message passing system will have a problem when two libraries
> > implement same message name on the same object.
> >
> > BUT, generic function system will have a problem when two libraries
> > implement same message name on the same **package**, not object.
> >
> [...]
>
> > Generic function is a semantic/contract/interface name; it is tied to a
> > package, not any object or class. So instead of calling:
> >
> >  (name person)
> >
> > You have to call:
> >
> >  (person:name person)
> >
> > But why can't message be resolved only by name and not its package?
> > It is because function is global. The look up mechanism of function is
> > in global namespace. Since you don't look up a method through object,
> > but rather through environment, you will need something to give scope
> > to what method will be invoke.
> >
> > In case of message passing system, the fact that message only have name
> > is not a big trouble because the scope of message can be found easily
> > by its receiver.
>
> ...and yet in practice, the demand for module systems sooner or later
> comes up in languages which use only names to disambiguate messages, to
> be able to make finer distinctions. As soon as you have modules, you
> have to know more about the messages that you are sending apart from
> their names.
>

No, in practice, it is not a big trouble, as in hard to prevent with
some discipline, or else we would not see more and more of message
based language. I'm not saying there is no problem, just that it is not
big issue.

It is similar issue with Manifest static typing and dynamic typing
language. static type language capture more of semantic and interface
and it is better in theory, dynamic type can cause more issue, yet in
practice, human learn and gain productivity from relaxing from strict
interface contract.


Anyway, this has nothing to do with where I was replying to --
different between message-based and generic-function system.

So even though message based system is actually inferior to generic
function, it still stands that message based system is better at
implementing "method missing".

I have replied here about other problem with implementing "method
missing" with generic function.

http://groups.google.com/group/comp.lang.lisp/msg/313e0037ec074eac

>
> Pascal
>
> --
> 3rd European Lisp Workshop
> July 3 - Nantes, France - co-located with ECOOP 2006
> http://lisp-ecoop06.bknr.net/
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4fstlgF1jq7klU1@individual.net>
Pisin Bootvong wrote:
> Pascal Costanza wrote:
>> Pisin Bootvong wrote:
>>> Thomas A. Russ wrote:
>>>> Well, I would think that a message-passing system would have similar
>>>> problems, wouldn't it?  What if you have two libraries that both
>>>> implement the same message on the same object?  You would have the same
>>>> name clash.
>>> Yes, message passing system will have a problem when two libraries
>>> implement same message name on the same object.
>>>
>>> BUT, generic function system will have a problem when two libraries
>>> implement same message name on the same **package**, not object.
>>>
>> [...]
>>
>>> Generic function is a semantic/contract/interface name; it is tied to a
>>> package, not any object or class. So instead of calling:
>>>
>>>  (name person)
>>>
>>> You have to call:
>>>
>>>  (person:name person)
>>>
>>> But why can't message be resolved only by name and not its package?
>>> It is because function is global. The look up mechanism of function is
>>> in global namespace. Since you don't look up a method through object,
>>> but rather through environment, you will need something to give scope
>>> to what method will be invoke.
>>>
>>> In case of message passing system, the fact that message only have name
>>> is not a big trouble because the scope of message can be found easily
>>> by its receiver.
>> ...and yet in practice, the demand for module systems sooner or later
>> comes up in languages which use only names to disambiguate messages, to
>> be able to make finer distinctions. As soon as you have modules, you
>> have to know more about the messages that you are sending apart from
>> their names.
>>
> 
> No, in practice, it is not a big trouble, as in hard to prevent with
> some discipline, or else we would not see more and more of message
> based language. I'm not saying there is no problem, just that it is not
> big issue.

Likewise, it doesn't seem to be a big issue with generic functions as well.

Note that you are also referring to "some discipline" here, so we are 
"just" talking about different sets of conventions which allow you to 
deal with the respective weaknesses.

> Anyway, this has nothing to do with where I was replying to --
> different between message-based and generic-function system.
> 
> So even though message based system is actually inferior to generic
> function, it still stands that message based system is better at
> implementing "method missing".

No, I really don't think so. It's correct that in a message-based 
language, it is easier to set up objects that can blindly forward any 
kind of message they receive to some other object that they wrap.

In a function-centric setting, like CLOS, this is not so 
straightforward, but you are comparing apples and oranges when you do 
that. The functional equivalent to an object wrapper in a message-based 
system is a functional wrapper. Like this:

(defun generate-wrapper (f)
   (lambda (&rest args)
     (apply f args)))

This also creates a function that blindly forwards all function calls to 
another function.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150901799.581567.223780@u72g2000cwu.googlegroups.com>
Pascal Costanza wrote:
> Pisin Bootvong wrote:
> > [snip]
> > So even though message based system is actually inferior to generic
> > function, it still stands that message based system is better at
> > implementing "method missing".
>
> No, I really don't think so. It's correct that in a message-based
> language, it is easier to set up objects that can blindly forward any
> kind of message they receive to some other object that they wrap.
>
> In a function-centric setting, like CLOS, this is not so
> straightforward, but you are comparing apples and oranges when you do
> that. The functional equivalent to an object wrapper in a message-based
> system is a functional wrapper. Like this:
>
> (defun generate-wrapper (f)
>    (lambda (&rest args)
>      (apply f args)))
>
> This also creates a function that blindly forwards all function calls to
> another function.
>

1. GENERATE-WRAPPER require user to call function in uncommon way.

 (funcall (generate-wrapper #'foo) obj arg)

Usual function call would look like this

 ((generate-wrapper #'foo) obj arg)

In meesage based system, client still call method te same way

obj.bar

------


2. Message-based method missing does NOT blindly forward call to other
method, they can decide what to do based on the message that is sent to
them. In message based system the code that handle method missing know
the method name to call.

So I can do this in Ruby

class Foo
  def method_missing(method_name, *args)
    puts "You call undefined method #{method_name}."
  end
end

You can use it like this.

 > obj = Foo.new
 > obj.foo
 => You call undefined method foo.
 > obj.bar
 => You call undefined method bar.

How could GENERATE-LAMBDA do that?

If I did:

 (let ((a-wrapper (generate-wrapper XXX))
   (setf (symbol-function 'foo) a-wrapper)
   (setf (symbol-function 'bar) a-wrapper))

What can I put in XXX to make a-wrapper know from which function it is
called from?

Also it is obvious here that you have to generate all function name
before hand, and client is only allow to call those predefined methods.


Either it is possible to do or it is not, whether it is Lisp way is
another topic.
If you could not do something in a language, how could you appreciate
that technique's usage?


> Pascal
>
> --
> 3rd European Lisp Workshop
> July 3 - Nantes, France - co-located with ECOOP 2006
> http://lisp-ecoop06.bknr.net/
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymiac8678t4.fsf@sevak.isi.edu>
"Pisin Bootvong" <··········@gmail.com> writes:

> 2. Message-based method missing does NOT blindly forward call to other
> method, they can decide what to do based on the message that is sent to
> them. In message based system the code that handle method missing know
> the method name to call.
> 
> So I can do this in Ruby
> 
> class Foo
>   def method_missing(method_name, *args)
>     puts "You call undefined method #{method_name}."
>   end
> end
> 
> You can use it like this.
> 
>  > obj = Foo.new
>  > obj.foo
>  => You call undefined method foo.
>  > obj.bar
>  => You call undefined method bar.

Unfortunately, Common Lisp, unlike Java, doesn't specify quite as rich a
required set of exception types.  What one would ideally like would be
to be able to write an error handler like this:

  (handler-case
     (bar obj)
   (NO-APPLICABLE-METHOD-ERROR (err)
      (format t "No method on ~S for ~S"
                (generic-function err)
                (arguments err))))

But since the standard only requires that the error raised by of type
ERROR, one can't really get portable, programmatic access to the parts
of the problem.

The NO-APPLICABLE-METHOD method is specialized only the generic
function, but there isn't any other choice, because dispatch is done by
generic function, not by class.

So this is something that goes against the design of the object system.

I would bet that you would have trouble writing a single method in Ruby
that would handle ALL missing methods named "baz", regardless of which
object they were invoked on.  Your only choice would be to include it in
the top level class (which I presume you can't add methods to in Ruby)
or else to write one in the root class of ALL user-defined classes.

In Common Lisp it is trivial:

(defgeneric baz (arg1 arg2 arg3))
(defmethod no-applicable-method 
   ((generic-function #'baz) arg1 arg2 arg3))




-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150912735.284937.102100@c74g2000cwc.googlegroups.com>
Thomas A. Russ wrote:
[snip]
> I would bet that you would have trouble writing a single method in Ruby
> that would handle ALL missing methods named "baz", regardless of which
> object they were invoked on.  Your only choice would be to include it in
> the top level class (which I presume you can't add methods to in Ruby)
> or else to write one in the root class of ALL user-defined classes.

I'll take that bet. In Ruby all classes are open unless you
specifically freeze them. What that means is that you can add methods
to even the root class (class Object) if you want, even at run-time.
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymizmg55b58.fsf@sevak.isi.edu>
"vanekl" <·····@acd.net> writes:

> Thomas A. Russ wrote:
> [snip]
> > I would bet that you would have trouble writing a single method in Ruby
> > that would handle ALL missing methods named "baz", regardless of which
> > object they were invoked on.  Your only choice would be to include it in
> > the top level class (which I presume you can't add methods to in Ruby)
> > or else to write one in the root class of ALL user-defined classes.
> 
> I'll take that bet. In Ruby all classes are open unless you
> specifically freeze them. What that means is that you can add methods
> to even the root class (class Object) if you want, even at run-time.

OK.
Looks like I missed a bit on the assumptions side.


I guess I'll need to take a look at Ruby one of these days.
This does make things a bit more flexible, which is nice.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4g22o0F1j8p4mU2@individual.net>
Thomas A. Russ wrote:
> "vanekl" <·····@acd.net> writes:
> 
>> Thomas A. Russ wrote:
>> [snip]
>>> I would bet that you would have trouble writing a single method in Ruby
>>> that would handle ALL missing methods named "baz", regardless of which
>>> object they were invoked on.  Your only choice would be to include it in
>>> the top level class (which I presume you can't add methods to in Ruby)
>>> or else to write one in the root class of ALL user-defined classes.
>> I'll take that bet. In Ruby all classes are open unless you
>> specifically freeze them. What that means is that you can add methods
>> to even the root class (class Object) if you want, even at run-time.
> 
> OK.
> Looks like I missed a bit on the assumptions side.
> 
> I guess I'll need to take a look at Ruby one of these days.
> This does make things a bit more flexible, which is nice.

BTW, you get this kind of openness already in Smalltalk.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150912981.672040.142500@i40g2000cwc.googlegroups.com>
Thomas A. Russ wrote:
> "Pisin Bootvong" <··········@gmail.com> writes:
>
> > 2. Message-based method missing does NOT blindly forward call to other
> > method, they can decide what to do based on the message that is sent to
> > them. In message based system the code that handle method missing know
> > the method name to call.
> >
> > So I can do this in Ruby
> >
> > class Foo
> >   def method_missing(method_name, *args)
> >     puts "You call undefined method #{method_name}."
> >   end
> > end
> >
> > You can use it like this.
> >
> >  > obj = Foo.new
> >  > obj.foo
> >  => You call undefined method foo.
> >  > obj.bar
> >  => You call undefined method bar.
>
> Unfortunately, Common Lisp, unlike Java, doesn't specify quite as rich a
> required set of exception types.  What one would ideally like would be
> to be able to write an error handler like this:
>
>   (handler-case
>      (bar obj)
>    (NO-APPLICABLE-METHOD-ERROR (err)
>       (format t "No method on ~S for ~S"
>                 (generic-function err)
>                 (arguments err))))
>
> But since the standard only requires that the error raised by of type
> ERROR, one can't really get portable, programmatic access to the parts
> of the problem.
>
> The NO-APPLICABLE-METHOD method is specialized only the generic
> function, but there isn't any other choice, because dispatch is done by
> generic function, not by class.
>
> So this is something that goes against the design of the object system.
>
> I would bet that you would have trouble writing a single method in Ruby
> that would handle ALL missing methods named "baz", regardless of which
> object they were invoked on.  Your only choice would be to include it in
> the top level class (which I presume you can't add methods to in Ruby)
> or else to write one in the root class of ALL user-defined classes.
>

Well, your assumption was wrong :-)
Class in Ruby is open class, so you can add method to handle that to
root class.

> In Common Lisp it is trivial:
>
> (defgeneric baz (arg1 arg2 arg3))
> (defmethod no-applicable-method
>    ((generic-function #'baz) arg1 arg2 arg3))
>
>

In ruby I would do

 class Object
    def baz
       ...
    end
 end

> -- 
> Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4ft6i3F1k4l1lU1@individual.net>
Pisin Bootvong wrote:
> Pascal Costanza wrote:
>> Pisin Bootvong wrote:
>>> [snip]
>>> So even though message based system is actually inferior to generic
>>> function, it still stands that message based system is better at
>>> implementing "method missing".
>> No, I really don't think so. It's correct that in a message-based
>> language, it is easier to set up objects that can blindly forward any
>> kind of message they receive to some other object that they wrap.
>>
>> In a function-centric setting, like CLOS, this is not so
>> straightforward, but you are comparing apples and oranges when you do
>> that. The functional equivalent to an object wrapper in a message-based
>> system is a functional wrapper. Like this:
>>
>> (defun generate-wrapper (f)
>>    (lambda (&rest args)
>>      (apply f args)))
>>
>> This also creates a function that blindly forwards all function calls to
>> another function.
>>
> 
> 1. GENERATE-WRAPPER require user to call function in uncommon way.
> 
>  (funcall (generate-wrapper #'foo) obj arg)
> 
> Usual function call would look like this
> 
>  ((generate-wrapper #'foo) obj arg)
> 
> In meesage based system, client still call method te same way
> 
> obj.bar

No, you're comparing apples and oranges. The call obj.bar will only go 
through a wrapper when obj is a reference to a wrapper of the object 
that you actually want to send the message to. You have just omitted the 
wrapping in your code example.

I can as well omit the wrapping by giving the example like this:

(foo obj args) or (funcall foo obj args)

There are several ways to get there. For example:

(setf (symbol-function 'foo) (generate-wrapper #'foo))

or simply:

(defun do-something (foo)
   (funcall foo obj args))

...and rely on the fact that you are passed a "correctly" wrapped 
function. (That's what you more or less do in the obj.foo example as well.)

> 2. Message-based method missing does NOT blindly forward call to other
> method, they can decide what to do based on the message that is sent to
> them. In message based system the code that handle method missing know
> the method name to call.
> 
> So I can do this in Ruby
> 
> class Foo
>   def method_missing(method_name, *args)
>     puts "You call undefined method #{method_name}."
>   end
> end
> 
> You can use it like this.
> 
>  > obj = Foo.new
>  > obj.foo
>  => You call undefined method foo.
>  > obj.bar
>  => You call undefined method bar.
> 
> How could GENERATE-LAMBDA do that?

(defun generate-wrapper (fun)
   (lambda (receiver &rest args)
     (typecase receiver
       (foo (error "You called the undefined function ~S."
                   (nth-value 2 (function-lambda-expression fun))))
       (t (apply fun receiver args)))))

> If I did:
> 
>  (let ((a-wrapper (generate-wrapper XXX))
>    (setf (symbol-function 'foo) a-wrapper)
>    (setf (symbol-function 'bar) a-wrapper))
> 
> What can I put in XXX to make a-wrapper know from which function it is
> called from?

I am not sure whether you really mean what you're asking for, but you 
should be aware that in OO languages you typically don't know who sent a 
message to you as well.

If you want to know who called a function, you can do this:

(defvar *called-from-g* nil)

(let ((org-g #'g))
   (setf (symbol-function 'g)
         (lambda (&rest args)
           (let ((*called-from-g* t))
             (apply org-g args)))))

(defun generate-wrapper (fun)
   (lambda (&rest args)
     (if *called-from-g*
       (error "You are not allowed to call ~S from G."
              (nth-value (function-lambda-expression fun)))
       (apply fun args))))


> Also it is obvious here that you have to generate all function name
> before hand, and client is only allow to call those predefined methods.

...and you have to create all objects beforehand and clients are only 
allowed to send messages to those objects. ;)



Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150914461.344810.7500@u72g2000cwu.googlegroups.com>
Pascal Costanza wrote:
> Pisin Bootvong wrote:
> > Pascal Costanza wrote:
> >> Pisin Bootvong wrote:
> >>> [snip]
> >>> So even though message based system is actually inferior to generic
> >>> function, it still stands that message based system is better at
> >>> implementing "method missing".
> >> No, I really don't think so. It's correct that in a message-based
> >> language, it is easier to set up objects that can blindly forward any
> >> kind of message they receive to some other object that they wrap.
> >>
> >> In a function-centric setting, like CLOS, this is not so
> >> straightforward, but you are comparing apples and oranges when you do
> >> that. The functional equivalent to an object wrapper in a message-based
> >> system is a functional wrapper. Like this:
> >>
> >> (defun generate-wrapper (f)
> >>    (lambda (&rest args)
> >>      (apply f args)))
> >>
> >> This also creates a function that blindly forwards all function calls to
> >> another function.
> >>
> >
> > 1. GENERATE-WRAPPER require user to call function in uncommon way.
> >
> >  (funcall (generate-wrapper #'foo) obj arg)
> >
> > Usual function call would look like this
> >
> >  ((generate-wrapper #'foo) obj arg)
> >
> > In meesage based system, client still call method te same way
> >
> > obj.bar
>
> No, you're comparing apples and oranges. The call obj.bar will only go
> through a wrapper when obj is a reference to a wrapper of the object
> that you actually want to send the message to. You have just omitted the
> wrapping in your code example.
>

No, no, no. "obj" is the real target object. it is not wrapper. It just
happens that "obj" also knows how handle unknown message.

 class Person
   def name ... end  # some predefined method
   def method_missing ... end  # can also handle unknown message.
end

> I can as well omit the wrapping by giving the example like this:
>
> (foo obj args) or (funcall foo obj args)
>
> There are several ways to get there. For example:
>
> (setf (symbol-function 'foo) (generate-wrapper #'foo))
>
> or simply:
>
> (defun do-something (foo)
>    (funcall foo obj args))
>
> ...and rely on the fact that you are passed a "correctly" wrapped
> function. (That's what you more or less do in the obj.foo example as well.)
>
> > 2. Message-based method missing does NOT blindly forward call to other
> > method, they can decide what to do based on the message that is sent to
> > them. In message based system the code that handle method missing know
> > the method name to call.
> >
> > So I can do this in Ruby
> >
> > class Foo
> >   def method_missing(method_name, *args)
> >     puts "You call undefined method #{method_name}."
> >   end
> > end
> >
> > You can use it like this.
> >
> >  > obj = Foo.new
> >  > obj.foo
> >  => You call undefined method foo.
> >  > obj.bar
> >  => You call undefined method bar.
> >
> > How could GENERATE-LAMBDA do that?
>
> (defun generate-wrapper (fun)
>    (lambda (receiver &rest args)
>      (typecase receiver
>        (foo (error "You called the undefined function ~S."
>                    (nth-value 2 (function-lambda-expression fun))))
>        (t (apply fun receiver args)))))
>
> > If I did:
> >
> >  (let ((a-wrapper (generate-wrapper XXX))
> >    (setf (symbol-function 'foo) a-wrapper)
> >    (setf (symbol-function 'bar) a-wrapper))
> >
> > What can I put in XXX to make a-wrapper know from which function it is
> > called from?
>
> I am not sure whether you really mean what you're asking for, but you
> should be aware that in OO languages you typically don't know who sent a
> message to you as well.
>

Sorry for my bad English. I meant in method missing handler you would
know what is the name of that "unknown message" that was sent. But in
case of your wrapper you wouldn't by what know the name of your
function that was called.

> If you want to know who called a function, you can do this:
>
> (defvar *called-from-g* nil)
>
> (let ((org-g #'g))
>    (setf (symbol-function 'g)
>          (lambda (&rest args)
>            (let ((*called-from-g* t))
>              (apply org-g args)))))
>
> (defun generate-wrapper (fun)
>    (lambda (&rest args)
>      (if *called-from-g*
>        (error "You are not allowed to call ~S from G."
>               (nth-value (function-lambda-expression fun)))
>        (apply fun args))))
>
>

In my example, only one handler is required to handle any number of
unknown messages, your GENERATE-WRAPPER only work on one message,
whatever, you DEFUN result of GENERATE-WRAPPER to.

> > Also it is obvious here that you have to generate all function name
> > before hand, and client is only allow to call those predefined methods.
>
> ...and you have to create all objects beforehand and clients are only
> allowed to send messages to those objects. ;)
>

I think you were referring to wrapper object, since you misunderstood,
this point is mute.

>
>
> Pascal
>
> --
> 3rd European Lisp Workshop
> July 3 - Nantes, France - co-located with ECOOP 2006
> http://lisp-ecoop06.bknr.net/
From: sross
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150875836.263004.29410@m73g2000cwd.googlegroups.com>
> Sorry, I don't have the time right now to look for the CL equivalent.
> Perhaps someone else does?

Well, CL's approach for accessing slots seems to be message-passing
based (at least in spirit) so we could do this.
[apologies for broken indenting]

(defclass hash-slot-mixin ()
  ((hashed-slots :accessor hashed-slots-of :initform (make-hash-table)
   :initarg :hashed-slots)))

(defmethod slot-missing ((class standard-class) (obj hash-slot-mixin)
                                     slot-name op &optional new-value)
  (with-slots (hashed-slots) obj
    (ecase op
      (slot-value (gethash slot-name hashed-slots))
      (setf (setf (gethash slot-name hashed-slots) new-value))
      (slot-boundp (nth-value 1 (gethash slot-name hashed-slots)))
      (slot-makunbound (remhash slot-name hashed-slots)))))


(defclass record-row (hash-slot-mixin) ())

;; we can now access the values in the hash-table as slots
(with-slots (a b c d) my-instance
  (list a b c d))

;; or add new ones
(with-slots (e f g h) my-instance
  (setf e 1 f 2 g 3 h 4))

Granted this is an example where the function call can be effectively
replaced by accessing a slot. More complex variants will be far
more difficult to duplicate, quite possibly to a point where this
approach is just The Wrong Thing.

Cheers,
  Sean.
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4fo43fF1i252eU1@individual.net>
vanekl wrote:
> Joe Marshall wrote:
>> vanekl wrote:
>>> Message passing is powerful, but I don't think CL uses
>>> it. That's one thing I miss from using Ruby. Method_missing allowed you
>>> to catch problems at runtime and adjust (or even eval a new method).
>> Message passing is semantically equivalent to function calling.  I
>> think CL has that.
> 
> So are you saying that it's possible to call a method that doesn't
> exist, catch the error, define the non-existent method, and then invoke
> it, all at runtime?

Yes, this is possible. All you need is to define the respective generic 
function. See no-applicable-method, which is part of ANSI Common Lisp.

The fact that you need a generic function to deal with non-existent 
methods might seem as a disadvantage at first, but CLOS is indeed 
function-centric and not object-centric. In an object-centric language, 
you still need an object to which you send a message so that a "message 
not understood" mechanism can be invoked at runtime.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: vanekl
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150741224.784976.213900@g10g2000cwb.googlegroups.com>
Pascal Costanza wrote:
> vanekl wrote:
> > Joe Marshall wrote:
> >> vanekl wrote:
> >>> Message passing is powerful, but I don't think CL uses
> >>> it. That's one thing I miss from using Ruby. Method_missing allowed you
> >>> to catch problems at runtime and adjust (or even eval a new method).
> >> Message passing is semantically equivalent to function calling.  I
> >> think CL has that.
> >
> > So are you saying that it's possible to call a method that doesn't
> > exist, catch the error, define the non-existent method, and then invoke
> > it, all at runtime?
>
> Yes, this is possible. All you need is to define the respective generic
> function. See no-applicable-method, which is part of ANSI Common Lisp.
>
> The fact that you need a generic function to deal with non-existent
> methods might seem as a disadvantage at first, but CLOS is indeed
> function-centric and not object-centric. In an object-centric language,
> you still need an object to which you send a message so that a "message
> not understood" mechanism can be invoked at runtime.
>
>
> Pascal

Even though the solution you present does not mimic message passing
behavior, I can see the analogy you are making, which I concede is
valid.

Thank you,

Lou Vanek
From: Thomas F. Burdick
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <xcvy7vs6ynx.fsf@conquest.OCF.Berkeley.EDU>
"vanekl" <·····@acd.net> writes:

> Pascal Costanza wrote:
>
> > >> vanekl wrote:
> >
> > > So are you saying that it's possible to call a method that doesn't
> > > exist, catch the error, define the non-existent method, and then invoke
> > > it, all at runtime?
> >
> > Yes, this is possible. All you need is to define the respective generic
> > function. See no-applicable-method, which is part of ANSI Common Lisp.
> >
> > The fact that you need a generic function to deal with non-existent
> > methods might seem as a disadvantage at first, but CLOS is indeed
> > function-centric and not object-centric. In an object-centric language,
> > you still need an object to which you send a message so that a "message
> > not understood" mechanism can be invoked at runtime.
> 
> Even though the solution you present does not mimic message passing
> behavior, I can see the analogy you are making, which I concede is
> valid.

And since you were talking about Ruby, which is an implementation, not
a language standard -- we can do the exact same thing with functions
in Allegro CL.  Pascal spelled out what happens if you already have a
generic function; if the function is undefined, you'll get an
undefined-function error.  Handle this, define the appropriate generic
function and any methods you want, and invoke the try-again restart.
(CL condition handlers do not by default unwind the stack, and other
implementations may have similar condition/restart pairs to do what I
described here).
From: Pisin Bootvong
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <1150795788.589223.50490@y41g2000cwy.googlegroups.com>
Thomas F. Burdick wrote:
> "vanekl" <·····@acd.net> writes:
>
> > Pascal Costanza wrote:
> >
> > > >> vanekl wrote:
> > >
> > > > So are you saying that it's possible to call a method that doesn't
> > > > exist, catch the error, define the non-existent method, and then invoke
> > > > it, all at runtime?
> > >
> > > Yes, this is possible. All you need is to define the respective generic
> > > function. See no-applicable-method, which is part of ANSI Common Lisp.
> > >
> > > The fact that you need a generic function to deal with non-existent
> > > methods might seem as a disadvantage at first, but CLOS is indeed
> > > function-centric and not object-centric. In an object-centric language,
> > > you still need an object to which you send a message so that a "message
> > > not understood" mechanism can be invoked at runtime.
> >
> > Even though the solution you present does not mimic message passing
> > behavior, I can see the analogy you are making, which I concede is
> > valid.
>
> And since you were talking about Ruby, which is an implementation, not
> a language standard -- we can do the exact same thing with functions
> in Allegro CL.  Pascal spelled out what happens if you already have a
> generic function; if the function is undefined, you'll get an
> undefined-function error.  Handle this, define the appropriate generic
> function and any methods you want, and invoke the try-again restart.
> (CL condition handlers do not by default unwind the stack, and other
> implementations may have similar condition/restart pairs to do what I
> described here).

1. Undefined-function condition only contains function name, not the
argument to function. So you can only define generic function or method
special on T (because you don't know the type of object being invoked).
Does Allegro CL undefined-function condition extend this?

2. You have to install condition handler for undefined function, so
while Ruby or Smalltalk client code is:

 obj.undefine_function

Lisp code will be:

 (with-libx-missing-method-handler
    (undefine-function obj))

Which means there is leaky abstraction here (client now knows you are
using method-missing technique).

3. There can be only one handler for a condition at a time, therefore
it is not possible for two library to work together if they both use
undefine-function approach.

 (with-libx-missing-method-handler
    (with-liby-missing-method-handler
       (undefine-function obj))            ;; this will always invoke
handler of liby

Where as in Ruby/Smalltalk:

x = LibxObject.new
y = LibYObject.new

x.foo              # both works
y.foo

4. Whether Ruby is standardized or not is red herring. The method
missing mechanism of Ruby is taken from Smalltalk.
The mechanism is to be evaluated by itself, not requiring the
implemented language to be standaized.
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <73klg.1229$PG4.834@fe12.lga>
Pascal Bourguignon wrote:
> "vanekl" <·····@acd.net> writes:
> 
>>Personally, I would be most interested in seeing how to iterate through
>>each slot without having to know the slot names a priori.
> 
> 
> [211]> (asdf:oos 'asdf:load-op :closer-mop)
> ...
> [212]> (defclass c1 () (a b))
> #1=#<STANDARD-CLASS C1>
> [213]> (defclass c2 (c1) (d e f))
> #1=#<STANDARD-CLASS C2>
> [214]> (closer-mop:compute-slots (find-class 'c2))
> (#<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION A #x2052E666>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION B #x2052E6A6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION D #x2052E6E6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION E #x2052E726>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION F #x2052E766>)
> 
> [217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
>          (print (closer-mop:slot-definition-name slot)))
> 
> A 
> B 
> D 
> E 
> F 
> NIL
> 

Funny, I get:

      55,167,995 bytes reclaimed
           1,342 bytes used
114,972,962,816 bytes free

:)

kenny

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4fm1e6F1jvmocU1@individual.net>
Pascal Bourguignon wrote:
> "vanekl" <·····@acd.net> writes:
>> Personally, I would be most interested in seeing how to iterate through
>> each slot without having to know the slot names a priori.
> 
> [211]> (asdf:oos 'asdf:load-op :closer-mop)
> ...
> [212]> (defclass c1 () (a b))
> #1=#<STANDARD-CLASS C1>
> [213]> (defclass c2 (c1) (d e f))
> #1=#<STANDARD-CLASS C2>
> [214]> (closer-mop:compute-slots (find-class 'c2))
> (#<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION A #x2052E666>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION B #x2052E6A6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION D #x2052E6E6>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION E #x2052E726>
>  #<CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION F #x2052E766>)
> 
> [217]> (dolist (slot (closer-mop:compute-slots (find-class 'c2)))
>          (print (closer-mop:slot-definition-name slot)))
> 
> A 
> B 
> D 
> E 
> F 
> NIL

compute-slots goes through the process of collecting all the direct slot 
definitions, combining them and computing each effective slot. In 
general, you don't need that overhead, but calling class-slots is enough 
to get the already computed & cached list of slots.

In general, a good rule of thumb for using the CLOS MOP is that you 
shouldn't call compute-xyz functions yourself, but only define methods 
on them so that the CLOS implementation can call them.

(It can be that, depending on the CLOS implementation, class-slots 
doesn't give you the list of slots when you haven't made instances of 
that class yet. Calling finalize-inheritance first fixes this problem.)


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <B2elg.373$PG4.135@fe12.lga>
Benjamin Teuber wrote:
> Hi,
> 
> I'll have to hold an interactive presentation at a seminar called 
> "Aspects of Object-Oriented Languages". "Interactive" means I will 
> present an unfinished or bad program which the others have to rewrite 
> and finish together.

Cool! And you have twenty minutes, right? (How much time do you have?)

My first observation: you say "unfinished or bad". Make up your mind, 
dammit! Sorry. I mean: covering both kinda doubles the scope. "bad" will 
be really hard, because it is hard to generate authentic bad code. It is 
easy to generate ridiculous code no one would ever write (although they 
do). Assuming you are an OO God, maybe you could look at the standard OO 
"Thou shalt not" commandments and create a simple class that violates 
them all one way or another. Especially neat would be not using fancy 
CLOS/GF mechanisms when violating, say, encapsulation and then using the 
good stuff to cure. Extra credit for that. Otherwise, yeah, use GFs and 
initforms and initialize-instance badly and then fix.

Unfinished is easier. I always use a boiler for example code. There is a 
flame that is on or off, a temperature, a pressure, a release valve. 
Then the engineers go modular and the temperature comes from one of 
several thermometers that can be installed. uh-oh, all this code says:

     (temperature boiler)

No problemo, write an around method on temperature. If call-next-method 
returns a number (or number-units pair (another incremental enhancement 
being to support Fahrenheit or Celsius)) we are done, if not call 
temperature on the returned value.

Stuff like that.

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Benjamin Teuber
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <e75j4a$9j$1@kohl.informatik.uni-bremen.de>
Ken Tilton wrote:

> Cool! And you have twenty minutes, right? (How much time do you have?)

Something like one and a half hours, if I want.

> 
> My first observation: you say "unfinished or bad". Make up your mind, 
> dammit! Sorry. I mean: covering both kinda doubles the scope. "bad" will 
> be really hard, because it is hard to generate authentic bad code. It is 
> easy to generate ridiculous code no one would ever write (although they 
> do). Assuming you are an OO God, maybe you could look at the standard OO 
> "Thou shalt not" commandments and create a simple class that violates 
> them all one way or another. Especially neat would be not using fancy 
> CLOS/GF mechanisms when violating, say, encapsulation and then using the 
> good stuff to cure. Extra credit for that. Otherwise, yeah, use GFs and 
> initforms and initialize-instance badly and then fix.
> 
> Unfinished is easier. I always use a boiler for example code. There is a 
> flame that is on or off, a temperature, a pressure, a release valve. 
> Then the engineers go modular and the temperature comes from one of 
> several thermometers that can be installed. uh-oh, all this code says:
> 
>     (temperature boiler)
> 
> No problemo, write an around method on temperature. If call-next-method 
> returns a number (or number-units pair (another incremental enhancement 
> being to support Fahrenheit or Celsius)) we are done, if not call 
> temperature on the returned value.
> 
> Stuff like that.
> 

Thanks for your suggestions. I don't understand what is returned by the 
inner method in the second case and why you call temperature again on it.

Ben
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <Ngwlg.1273$PG4.347@fe12.lga>
Benjamin Teuber wrote:
> Ken Tilton wrote:
> 
>> Cool! And you have twenty minutes, right? (How much time do you have?)
> 
> 
> Something like one and a half hours, if I want.

Excellent.

>> Then the engineers go modular and the temperature comes from one of 
>> several thermometers that can be installed. uh-oh, all this code says:
>>
>>     (temperature boiler)
>>
>> No problemo, write an around method on temperature. If 
>> call-next-method returns a number (or number-units pair (another 
>> incremental enhancement being to support Fahrenheit or Celsius)) we 
>> are done, if not call temperature on the returned value.
>>
>> Stuff like that.
>>
> 
> Thanks for your suggestions. I don't understand what is returned by the 
> inner method in the second case and why you call temperature again on it.

Oh, sorry, I was typing, not thinking; that is nonsense. I'll try again:

The around method on temperature looks for a value in a new thermometer 
slot. if it finds one it calls temperature on that, if not it continues 
with call-next-method assuming we have an older design boiler that does 
not have a separate thermometer.

Or you can make a new subclass to support new types of boilers, forcing 
the code to make the right kind of instance for each model boiler. Then 
you add the thermometer slot only to that and /remove/ the temperature 
slot. To support code that says (temperature boiler) you just add a GF:

   (defmethod temperature ((self boiler-with-separate-thermo))
     (temperature (thermometer self)))

Hey, this is neat, it shows the advantage of always accessing a slot via 
an accessor, and slot accessors being simply GFs you can author by hand.

Note that you also need to define:

   (defmethod (setf temperature) (new-temp (self 
boiler-with-separate-thermo))
     (setf (temperature (thermometer self)) new-temp))

That gets called from the thermometer device driver.

Now suppose you want to have an alarm go off if the temperature gets too 
high, and you are not lucky enough to be using Cells (let's not scare 
the newbys).

You can start with some bad code that has the device driver handle this. 
It is bad because the device driver should only detect anomalies in the 
device, and in this case the thermometer is working fine, it is the 
burner that has failed to shut down in response to a signal from the 
boiler logic. You fix the code with a before or after method on (setf 
temperature) that compares the new-value with a boiler max temperature 
rating. Hmm, maybe we should change to pressure since that sounds like 
something that really would vary from boiler to boiler.

You could set things up beforehand by presenting around, before, after, 
call-next-method in the abstract and then hitting them with these little 
puzzles.

The boiler is neat because you have the burner, thermometer, pressure 
guage, water level, fuel level, alarms, release valves, all things you 
can add incrementally forcing the model to evolve and demonstrating 
CLOSes ability to morph gracefully.

In my building we had a nice case history with a controller developing a 
hardware issue such that its idea of the outside temperature read from a 
sensor bounced instantaneously up and down a few tenths of a degree. 
This in turned caused the controller to turn the burner on and off every 
  few tenths of a second, eventually causing the burner to get flooded 
at which point the system shut down. Now assume your model has an after 
method on the building temperature slot (or temperature slot of the 
building thermometer) that sends the on/off signal to the burner. You 
can write an around method that rejects wholesale jumpy assignments, or 
you can embed the intelligence "no matter what, do not send an on signal 
until five minutes after sending an off" in the after method talking to 
the burner. But let them figure that out.

Something like that.

btw, one idea for finding bad code: Google c.l.l for "help" and look for 
occasional cases where a newby posts newby code and folks weigh in with 
improvements.

kenny

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Benjamin Teuber
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <e7j48q$kni$1@kohl.informatik.uni-bremen.de>
Interesting, Kenny, I'll try that.

Another two things I'm looking for:


-a killer-example for multi-methods
-a good one about somple MOP stuff (I just got the standard 
logging-class example until now)

Any more ideas?

Thanks,
Ben
From: Ken Tilton
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <JIang.2$V27.0@fe09.lga>
Benjamin Teuber wrote:
> Interesting, Kenny, I'll try that.
> 
> Another two things I'm looking for:
> 
> 
> -a killer-example for multi-methods

With others, I must say I do not use that much. But when I do... Cells. 
The slot observers have the signature:

    (slot-name self new-value old-value old-value-bound-p)

Normally one can get away with specializing on just the slot name (since 
I make mine distinctive) but specializing on the class of the owning 
instance is an obvious "wanna-do".

Probably the classic would be graphical rendering. Certainly I need to 
specialize on the thing rendered. But a lot of the logic is the same 
whether one is rendering to OpenGL, PDF, a win32 EMF, or even just a 
rectangle (to comput a bounding box)... kinda like print-object 
rendering to stdout, a file, or nil to produce a string (and maybe 
/that/ is your best example).

> -a good one about somple MOP stuff (I just got the standard 
> logging-class example until now)

Maybe it is time for me to look at using the MOP again now that CLisp 
has it. I get the same result by having a defclass wrapper and doing 
with macrology what might be done better with the MOP. But another 
classic would be wrapping a C object-oriented library such as GTk or Tk 
with CLOS. I have my deftk macro generate writer methods to shuttle 
SETFs over to Tk/C-land so the GUI stays informed. With the MOP I would 
have a distinct slot definition type for those slots (most) that map to 
Tk "classes", then specialize (setf slot-value-using-class) to trap 
writes in Lisp-land and pipe them over.

> 
> Any more ideas?

Cells and GUIs are amazing together.

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Timofei Shatrov
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <449eced8.3838858@news.readfreenews.net>
On Sat, 24 Jun 2006 12:29:40 +0200, Benjamin Teuber <······@web.de>
tried to confuse everyone with this message:

>Interesting, Kenny, I'll try that.
>
>Another two things I'm looking for:
>
>
>-a killer-example for multi-methods

I love multimethods. When everything is an object, they appear rather
naturally. For example, consider a game where you need to fight
monsters. Each monster has an ai method which returns an action object
(such as (make-instance 'go :direction :n)). To execute that action you
call (do-action monster (ai monster)). do-action is a multimethod:

(defgeneric do-action (monster action)
  (:documentation "Execute an action"))

 go action doesn't depend much on the monster, so you can write:

(defmethod do-action ((monster monster) (action go))
  (move-monster monster (direction action)))

 But what about fire elemental which burns all wooden items on the floor
when he steps on them? It's easy to add this functionality:

(defmethod do-action :after ((monster fire-elemental) (action go))
  (loop for item in (items-on-the-ground (position monster))
        when (flammablep (material item)) do (destroy item))
  (call-next-method))
    
I also had another multimethod, react which made monsters to react to
various events in the gameworld.

-- 
|Don't believe this - you're not worthless              ,gr---------.ru
|It's us against millions and we can't take them all... |  ue     il   |
|But we can take them on!                               |     @ma      |
|                       (A Wilhelm Scream - The Rip)    |______________|
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4gal2dF1lroc4U1@individual.net>
Benjamin Teuber wrote:
> Interesting, Kenny, I'll try that.
> 
> Another two things I'm looking for:
> 
> 
> -a killer-example for multi-methods

One of the killer examples for multi-methods is that you actually don't 
need them. ;) Consider the Visitor pattern: The goal here is to group 
methods according to their functionality, not to the classes on which 
they are defined. To make this work in language like Java, Smalltalk, 
etc., you have to simulate double-dispatch (i.e., multi-methods). 
However, as soon as you add multi-methods to your language, you have to 
move methods outside of the classes, and then you're free to group them 
in whatever way you want. This makes double-dispatch unnecessary for 
this particular case.

Of course, there are examples where multi-methods are actually convenient.

> -a good one about somple MOP stuff (I just got the standard 
> logging-class example until now)

The example I typically use is where you store slots in hashtables 
instead of in arrays, as is the default. This is nice, because from 
there you can easily generalize to database access (where slots are 
stored in databases), which seems to be one of the most common uses of 
the CLOS MOP.

Another common use is to add observer functionality to slot accessors, 
that is, a machinery that allows you to be notified whenever a slot 
changes. (You could then even mention cells here... ;)

> Any more ideas?

Try to include something where you change class definitions at runtime, 
so you can notice that existing objects are affected. For example, 
define a mixin class with some behavior that gets added to existing objects.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Jack Unrue
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <f9f0a2hh7c1fimrtl2a8fjvr82ge5n462o@4ax.com>
On Mon, 26 Jun 2006 19:50:05 +0200, Pascal Costanza <··@p-cos.net> wrote:
>
>Benjamin Teuber wrote:
>> 
>> -a killer-example for multi-methods
>
>One of the killer examples for multi-methods is that you actually don't 
>need them. ;) Consider the Visitor pattern: The goal here is to group 
>methods according to their functionality, not to the classes on which 
>they are defined. To make this work in language like Java, Smalltalk, 
>etc., you have to simulate double-dispatch (i.e., multi-methods). 
>However, as soon as you add multi-methods to your language, you have to 
>move methods outside of the classes, and then you're free to group them 
>in whatever way you want. This makes double-dispatch unnecessary for 
>this particular case.
>
>Of course, there are examples where multi-methods are actually convenient.

I'm sure I'm not the first to discover that multi-methods help
increase reusability. :-) But in my experience this is one of
the big benefits.

For instance, say you have a class hierarchy and a generic function
that applies to any instance from that hierarchy (ye olde polymorphism).
Then you realize that the existing base class is conceptually two
separate roles, so you refactor the hierarchy, and the generic function
now splits what used to be 'self' into two arguments on which methods can
be specialized independently. In this example, the purpose of the generic
function can remain the same as before.

Thanks to multi-methods, it's possible to fine-tune subclassing
in a fashion that's natural for the newly-split hierarchy, namely
specializing against parent classes now where it wasn't necessarily
possible before. And in so doing, achieving better reusability
of the method implementations (because the implementation(s) are allowed
to be more broadly applicable than traditional single-dispatch would
allow).

-- 
Jack Unrue
From: Pascal Costanza
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <4flhjuF1j928dU1@individual.net>
Benjamin Teuber wrote:
> Hi,
> 
> I'll have to hold an interactive presentation at a seminar called 
> "Aspects of Object-Oriented Languages". "Interactive" means I will 
> present an unfinished or bad program which the others have to rewrite 
> and finish together.
> 
> Of course, I chose CLOS as my topic, and now I'm pondering on which 
> aspects of CLOS to focus and what kind of application to give them.
> 
> I guess that advanced MOP-stuff could be too difficult for students that 
> never saw any Lisp (besides little Scheme-functions..), so my first idea 
> would be to focus on the generic-function-approach and multimethods as 
> one advantage of this view.

I agree that if you get the notion of generic functions across that you 
will have achieved a lot. Check out Peter Seibel's "Practical Common 
Lisp", or other tutorials on CLOS / generic functions for ideas.

> As an example, I could think of a simple math library with vectors and 
> matrices and a few overloaded operators.
> 
> This is what I've got until now, but I'm not too satisfied with it and 
> thought that maybe you could find some better examples or aspects of 
> CLOS I can integrate without asking too much of them.

The concrete examples can be very simple, but what works pretty well is 
to show coding in CLOS in action. That is, open a Common Lisp IDE of 
your choice and develop the code during the presentation. This, of 
course, requires some experience, but the advantage is that you will 
show lots of details between the lines that are otherwise hard to 
present. For example, the way the editor highlights parentheses, the way 
you interact with the IDE when you have a bug, the way redifining 
classes affects existing instances, and so on. In this way, you can also 
allow the audience ask questions about issues that you haven't prepared 
for your presentation.

This style of presentation can be stressful, especially when you have to 
deal with an unexpected bug. On the other hand, the advantage is that 
you don't need to nail everything upfront.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Benjamin Teuber
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <e75j9c$9j$2@kohl.informatik.uni-bremen.de>
Pascal Costanza wrote:

> The concrete examples can be very simple, but what works pretty well is 
> to show coding in CLOS in action. That is, open a Common Lisp IDE of 
> your choice and develop the code during the presentation. This, of 
> course, requires some experience, but the advantage is that you will 
> show lots of details between the lines that are otherwise hard to 
> present. For example, the way the editor highlights parentheses, the way 
> you interact with the IDE when you have a bug, the way redifining 
> classes affects existing instances, and so on. In this way, you can also 
> allow the audience ask questions about issues that you haven't prepared 
> for your presentation.

Actually this is exactly the way it should be, although I shouldn't do 
everything on my own but rather let them tell me what to do - but of 
course I'll be able to give them hints etc.

Thank you, I'll check PCL for more examples.

Ben
From: Thomas A. Russ
Subject: Re: Simple CLOS-Example needed
Date: 
Message-ID: <ymihd2h7y99.fsf@sevak.isi.edu>
Benjamin Teuber <······@web.de> writes:

> Hi,
> 
> I guess that advanced MOP-stuff could be too difficult for students that
> never saw any Lisp (besides little Scheme-functions..), so my first idea
> would be to focus on the generic-function-approach and multimethods as
> one advantage of this view.

Yes, that is one thing that would be good to cover.

One really different feature would be to emphasize how GFs are always
extensible.  One way to fit this lesson in would be to have some already
written "library" code that does just about all you want, except that
there are perhaps one or two behaviors that are missing.  You can then
explain how in the dominant OO model, your only choice would be to
subclass and add the functionality you need -- but then you can't use
any instances created by "factory" methods of the library.  In CLOS,
though, you just add the GFs to extend the library -- not requiring and
source code changes to the library.

Another cool thing to show would be to do the early part of the work
using one particular class definition, and then "discover" a need to
change the class definition later on in the tutorial.  Then demonstrate
how the already existing instances of the class have been updated by the
system to have the new structure!  (I would also have a bit of material
about the protocol for UPDATE-INSTANCE-FOR-REDEFINED-CLASS just in case
someone asks what happens if the slots change and you need to do
something special about that.  I probably wouldn't mention it unless
someone asks, though.  And then not go into very much detail -- just
show that it has been thought of and a mechanism is in place to handle
it.)


-- 
Thomas A. Russ,  USC/Information Sciences Institute