colored point redux (was: Re: What _is_ exciting about generic functions vs. message sending...)

Vadim Nasardinov <[email protected]> Sat, 24 Feb 2007 15:56:26 -0500
Newsgroups gmane.comp.lang.lightweight
Message-ID <[email protected]>
On Saturday 24 February 2007 11:37, Pascal Costanza wrote:
> This whole discussion about naming issues has deteriorated. I am
> sorry about this because I have taken a part in that. Now, I'd like
> to make an attempt to get this discussion back on track.
> 
> Here are two or three examples what generic functions buy you:
> 
> 1) Assume the standard OOP example of points and how to compare
> points. Here is an implementation in CLOS:
> 
> (defclass point ()
>    ((x :initarg :x :reader x)
>     (y :initarg :y :reader y)))
> 
> (defclass color-point (point)
>    ((c :initarg :color :reader color)))
> 
> (defmethod eqv ((obj1 point) (obj2 point))
>    (and (eql (x obj1) (x obj2))
>         (eql (y obj1) (y obj2))))
> 
> (defmethod eqv ((obj1 color-point) (obj2 color-point))
>    (and (call-next-method)
>         (eql (color obj1) (color obj2))))
> 
> All the implementations in single-dispatch languages I have seen are
> ugly and amount to simulating multiple dispatch.

Ah, the venerable the "colored point" example.  I know we've been
through this before:

    http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03953.html
    http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03983.html
    http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04068.html
    http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04073.html

... but here's the thing.  I like my EQV relationship to be

 (a) Reflexive (check)
 (b) Symmetric (check)
 (c) Transitive (???)

Here's what we've got:

 | $ sbcl
 | This is SBCL 1.0, an implementation of ANSI Common Lisp.
 | More information about SBCL is available at <http://www.sbcl.org/>.
 | 
 | SBCL is free software, provided as is, with absolutely no warranty.
 | It is mostly in the public domain; some portions are provided under
 | BSD-style licenses.  See the CREDITS and COPYING files in the
 | distribution for more information.
 | * (defclass point ()
 |    ((x :initarg :x :reader x)
 |     (y :initarg :y :reader y)))
 | 
 | #<STANDARD-CLASS POINT>
 | * (defclass color-point (point)
 |    ((c :initarg :color :reader color)))
 | 
 | #<STANDARD-CLASS COLOR-POINT>
 | * (defmethod eqv ((obj1 point) (obj2 point))
 |    (and (eql (x obj1) (x obj2))
 |         (eql (y obj1) (y obj2))))
 | STYLE-WARNING: implicitly creating new generic function EQV
 | 
 | #<STANDARD-METHOD EQV (POINT POINT) {100228B6B1}>
 | * (defmethod eqv ((obj1 color-point) (obj2 color-point))
 |    (and (call-next-method)
 |         (eql (color obj1) (color obj2))))
 | 
 | #<STANDARD-METHOD EQV (COLOR-POINT COLOR-POINT) {10023B4811}>
 | * (defun compare (point-name1 point1 point-name2 point2)
 |   (format t "eqv(~A ~A): ~A~%" point-name1 point-name2 (eqv point1 point2)))
 | 
 | COMPARE
 | * (let
 |     ((p      (make-instance 'point       :x 1 :y 1))
 |      (p-red  (make-instance 'color-point :x 1 :y 1 :color 'red))
 |      (p-blue (make-instance 'color-point :x 1 :y 1 :color 'blue)))
 |   (compare "p-red" p-red "p" p)
 |   (compare "p" p "p-blue" p-blue)
 |   (compare "p-red" p-red "p-blue" p-blue))
 | eqv(p-red p): T
 | eqv(p p-blue): T
 | eqv(p-red p-blue): NIL
 | NIL
 | * (quit)

No transitivity.

Don't get me wrong.  I do appreciate the fact that broken code can be
much terser in Lisp than it is in Java.  That _is_ very exciting.