From: Erik R.
Subject: Generics in Lisp?
Date: 
Message-ID: <1183739393.950583.308620@57g2000hsv.googlegroups.com>
Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
of generics.  Here's my question, can I defmethod a method that
requires its argument to be a subclass of more than one class?  For
instance, in Java, I could do:

public static <T extends MyBaseClass & Comparable<T>> boolean
doSomeComparison(T obj)
{
  // here, i'm guaranteed that my obj variable both extends
MyBaseClass AND implements Comparable.
}

(defmethod do-some-comparison ((obj my-base-class))
  ;; my obj variable might or might not extend some other class
  )

Am I making myself clear?  I understand from the hyperspec that the
"my-base-class" in the above code is a "parameter specializer".  Can
you specify more than one?  Like:

(defmethod do-some-comparison ((obj (my-base-class comparable)))
  ;; now obj is both for sure
  )

Any help?

Cheers,
Erik

From: ·············@gmail.com
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183744842.447348.317940@o61g2000hsh.googlegroups.com>
Hi Erik,

> Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
> of generics.  Here's my question, can I defmethod a method that
> requires its argument to be a subclass of more than one class?  For
> instance, in Java, I could do:
>
> public static <T extends MyBaseClass & Comparable<T>> boolean
> doSomeComparison(T obj)
> {
>   // here, i'm guaranteed that my obj variable both extends
> MyBaseClass AND implements Comparable.
> }

Java, by design, does not support multiple inheritance. However,
multiple inheritance can be useful in certain cases, and interfaces in
Java were introduced to address some of those cases. CLOS, on the
other hand, does support multiple inheritance, so interfaces are
useless (besides that, Java interfaces are basically collections of
methods, while in CLOS methods don't belong to classes but to generic
functions, so in CLOS interfaces woulnd't even make sense).

You can achieve the same behaviour of your Java example using multiple
inheritance:

(defclass my-comparable-base-class (my-base-class comparable) (...))

and thus

(defmethod do-some-comparison ((obj my-comparable-base-class))
  ;; here obj is guaranteed to subclass both my-base-class and
comparable
  )

I hope this answers your question.

Note though that introducing the Comparable class in CLOS is probably
unnecessary, if Comparable means "something which has a compareTo()
method". In fact, as I said earlier, in CLOS methods don't belong to
classes: so you could just write a compare method that specializes on
my-base-class, like

(defmethod compare ((obj my-base-class) some-other-obj) ...)

and still achieve the same result. Note that this is not less type-
safe than the previous case, because knowing that obj subclasses
comparable does not guarantee that a compare method specialized on my-
comparable-base-class exists: you should either write it anyway, or
fallback on a generic "compare" specialized on comparable, which knows
nothing about my-base-class.
But to do this (a generic compare method) you don't need the
comparable class, as you can just write

(defmethod compare (obj some-other-obj) ...)



Alessio
From: Erik R.
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183747761.162396.27750@n2g2000hse.googlegroups.com>
Wow, thanks for such a detailed response.  I didn't choose Comparable
for any specific reason, just because it's a commonly used interface.
Let me be a little bit more concrete about what I'm trying to
accomplish.

I've got two base classes, shown here in pseudo-java:
---
/** knows how to load/save itself from/to db */
class DbObject
{
  fetch();
  store();
}

/** a basic node in a tree with one parent and many children of the
same type */
class SelfParenting
{
  getParent();
  getChildren();
  getDepth();
  isAncestor();
}
---

And I've got more than one class that is both stored in the database
and forms a tree structure, for instance:
---
class Folder extends DbObject, SelfParenting
{
}

class Category extends DbObject, SelfParenting
{
}
---
These two classes are unrelated, and might actually extend more
specialized subclasses of DbObject or SelfParenting.

What I want to write is a function that doesn't care what type of
object is passed to it, as long as it extends both DbObject and
SelfParenting.  Like so:

public <T extends DbObject & SelfParenting> Collection<T>
loadDescendants(final T root)
{
  Collection<T> descendants = new ArrayList<T>();
  root.fetch(); // load from db
  descendants.add(root);
  for(T descendant : root.getChildren())
    descendants.addAll(loadDescendants(descendant));
  return descendants;
}

That was horribly inefficient and the wrong way to do it, but you get
my point.  It doesn't care about anything except that T's can be
loaded from the db and that they have children.

Translating to Lisp...

(defclass db-object () ())
(defmethod fetch (object db-object) ....)
(defmethod store (object db-object) ....)

(defclass self-parenting () ())
(defmethod parent (object self-parenting) ....)
(defmethod children (object self-parenting) ....)
(defmethod depth (object self-parenting) ....)
(defmethod ancestor-p (object self-parenting) ....)

and my subclasses:

(defclass folder (db-object self-parenting) ())
(defclass category (db-object self-parenting) ())

Now what I want is to be able to write my load-descendants method
exactly ONCE, not for each class where the db-object and self-
parenting hierarchy meet.

Does this make more sense?  It sounds like methods must match on
specific types, and can't do so on two general superclasses.  Please
tell me I'm wrong?

Thanks again for all the quick responses,

Erik
From: ·············@gmail.com
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183749707.402102.309590@r34g2000hsd.googlegroups.com>
@Erik:

ok, if I understand correctly you want a single loadDescendants
methods that works the same on every object which is a subclass of
DbObject AND SelfParenting. If that is the case, you could add an
extra level of subclassing, i.e.

(defclass self-parenting-db-object (self-parenting db-object) ...)

(defclass folder (self-parenting-db-object) ...)
(defclass category (self-parenting-db-object) ...)

(defmethod load-descendants (self-parenting-db-object) ...do stuff...)

such a method then would be applicable to both folder and category. Of
course if you're writing a library you should document this so that
users of the library would adopt the same convention (subclassing self-
parenting-db-object), which in Java instead would be enforced by the
compiler.
From: Erik R.
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183750401.627647.252610@c77g2000hse.googlegroups.com>
On Jul 6, 9:21 pm, ·············@gmail.com wrote:
> @Erik:
>
> ok, if I understand correctly you want a single loadDescendants
> methods that works the same on every object which is a subclass of
> DbObject AND SelfParenting. If that is the case, you could add an
> extra level of subclassing, i.e.
>
> (defclass self-parenting-db-object (self-parenting db-object) ...)
>
> (defclass folder (self-parenting-db-object) ...)
> (defclass category (self-parenting-db-object) ...)
>
> (defmethod load-descendants (self-parenting-db-object) ...do stuff...)
>
> such a method then would be applicable to both folder and category. Of
> course if you're writing a library you should document this so that
> users of the library would adopt the same convention (subclassing self-
> parenting-db-object), which in Java instead would be enforced by the
> compiler.

Right, except that the class diagram is deeper than that.  What I
really have is something more like:

(defclass db-object () ())
(defclass self-parenting () ())

(defclass project-a-db-object (db-object) ()) // project A specific
stuff
(defclass project-b-db-object (db-object) ()) // project B specific
stuff

(defclass special-self-parenting-doodad (self-parenting) ())

And THEN comes...

(defclass folder (project-a-db-object self-parenting) ())
(defclass category (project-b-db-object special-self-parenting-doodad)
())

In which case, as I understand it, my generic load-descendants method
CANNOT be applied to both folder and category  (where it could in
java).  Of course this is lisp, after all, so each implementation of
load-descendants could be generated trivially.

This is not a huge deal, it's just a pattern that I have used in some
java projects, and I wanted to understand how lisp handled it.  I've
learned a lot from this discussion already.

Thanks,
Erik
From: jayessay
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <m3zm29th4y.fsf@sirius.goldenthreadtech.com>
"Erik R." <·············@gmail.com> writes:

> (defclass db-object () ())
> (defclass self-parenting () ())
> 
> (defclass project-a-db-object (db-object) ()) // project A specific
> stuff
> (defclass project-b-db-object (db-object) ()) // project B specific
> stuff
> 
> (defclass special-self-parenting-doodad (self-parenting) ())
> 
> And THEN comes...
> 
> (defclass folder (project-a-db-object self-parenting) ())
> (defclass category (project-b-db-object special-self-parenting-doodad)
> ())
> 
> In which case, as I understand it, my generic load-descendants method
> CANNOT be applied to both folder and category  (where it could in

OK, in that case just make load-descendant a regular function - it
isn't really specialized for anything given your description so it
shouldn't even be generic.

Then just have it call the methods that are specialized: the fetch,
store, et.al. on the passed in object.  If the passed in object
doesn't have such a method it will signal an error.  So, you have,

(defun load-descendants (obj)
  ... (fetch obj ...) ...<whatever> ...)

And the only methods you need to implement are the ones you would need
to by subclassing either/or/and db-object and self-parenting.

I'd say this is a fairly standard technique for your situation.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: David Golden
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <KUxji.20739$j7.378411@news.indigo.ie>
Erik R. wrote:

> In which case, as I understand it, my generic load-descendants method
> CANNOT be applied to both folder and category  (where it could in
> java).  

The pass-the-same-object-as-two-arguments trick mentioned by Alex should
still work (and you could just supply a neater-looking wrapper that
always passes the object twice to the underlying gf, the underlying gf
would presumably be nonexported from your package and probably
be named beginning with % or something too...)
From: jayessay
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <m34pkhuxa0.fsf@sirius.goldenthreadtech.com>
"Erik R." <·············@gmail.com> writes:

> (defclass db-object () ())
> (defmethod fetch (object db-object) ....)
> (defmethod store (object db-object) ....)
> 
> (defclass self-parenting () ())
> (defmethod parent (object self-parenting) ....)
> (defmethod children (object self-parenting) ....)
> (defmethod depth (object self-parenting) ....)
> (defmethod ancestor-p (object self-parenting) ....)
> 
> and my subclasses:
> 
> (defclass folder (db-object self-parenting) ())
> (defclass category (db-object self-parenting) ())
> 
> Now what I want is to be able to write my load-descendants method
> exactly ONCE

This is where multiple inheritance comes in - you can't do that in
Java, and that appears to indicate that you can't/are not thinking
about it:

(defclass db-object/self-parenting (db-object self-parenthing) ...)

(defmethod load-descendants ((obj db-object/self-parenting) ...) ...)


(defclass new-both-obj-w/new (db-object/self-parenting ...) ...)

...

(load-descendants my-obj)

will work for any my-obj that is a db-object/self-parenting, e.g.,
new-both-obj-w/new or any other such or any other decscended from
such.

Of course you will still need to write specific methods for fetch and
store (unless fetch and store are totally general and can eat any
standard-object - that's doable, but probably not what you want...)


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: ·············@gmail.com
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183752585.390208.233280@n60g2000hse.googlegroups.com>
> This is where multiple inheritance comes in - you can't do that in
> Java, and that appears to indicate that you can't/are not thinking
> about it:

That's what I thought, too, but as Erik correctly pointed out it works
only if you have complete control over the class hierarchy. There are
cases in which you can't use multiple inheritance to achieve this
goal, because Java generics effectively work like a sort of type-based
pattern matching, which does not exist in CLOS. However I suspect that
it is much rarer in CLOS than in Java to have to use this technique,
and so Pascal's solution (write a regular function and do type
checking manually if needed) is probably the best. imho of course...
From: Rayiner Hashem
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183758260.374175.121330@o61g2000hsh.googlegroups.com>
If you want a single implementation of load-descendents, you don't
need a method at all. Just a simple function will do. Eg:

(defun load-descendents (root)
  (let ((wlist (list root)))
    (do-until (empty? wlist)
      (let ((top (pop wlist)))
        (fetch top)
        (iter (for child in (children top))
          (push child wlist))))
    wlist))

Where do-until and empty? are macros/functions that do the obvious
thing.
From: Pascal Bourguignon
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <87hcohqp4z.fsf@thalassa.lan.informatimago.com>
"Erik R." <·············@gmail.com> writes:
> What I want to write is a function that doesn't care what type of
> object is passed to it, as long as it extends both DbObject and
> SelfParenting.  Like so:
> [...]
> Does this make more sense?  It sounds like methods must match on
> specific types, and can't do so on two general superclasses.  Please
> tell me I'm wrong?

Yes, method dispatching is used to select a method in function of the
type of the arguments.  Of course, since T is a supertype of all
types, you can always write a method that could be selected for
undiscriminated types, but this is not the question.

You want to write a function tht doesn't care what type is passed to
it.  So you don't need a method.  Just define a function.   Now of
course your function will expect the object to extend both db-object
and self-parenting classes.  No problem with that.  But you have to
ask yourself what in means, in the scope of a dynamically typed
programming language like lisp.  What does it mean for an object to be
an instance of such or such classes, in the context of your function?
Nothing more than that some "interface" to this object is available to
your function, that is, you can call some functions with this object
as argument, and something meaningful happens.


Let's take a simple example: you want to write a function that doesn't
care what type of object is passed to it, as long as it implements the
ELT interface where an item in the object can be selected by integer
index.

(defun f (obj)
  (list (elt obj 0) (elt obj 2)))

And surprise! This function can be called on vectors, strings and lists:

(values (f "abcdef") (f #(1 2 3 4 5)) (f '(:one :two :three :four)))
--> (#\a #\c)
    (1 3)
    (:ONE :THREE)


So, what does it mean for an object to be both a db-object and a
self-parenting?  Perhaps that the functions fetch, store, parent,
children, and depth can be called with this object.  Why should your
function care about the exact data type of the object, as long as
these functions can be applied on it?  Just write your function and
forget about these irrelevant details.

(defun f (object)
  (fetch object)       
  (parent object)
  (children object)
  (store object)
  (depth object))

If you try to call it on an object that doesn't implement this
"interface", say: (f 42), somebody will signal an error.  If the
client really want to call f with 42, it only has to implement the
"interface":

(defmethod fetch    ((self integer)) self)
(defmethod store    ((self integer)) (print self))
(defmethod children ((self integer)) (factorize self))
(defmethod parent   ((self integer)) 1)
(defmethod depth    ((self integer)) (log self))

Et voil�!  Now you can call (f 42).



-- 
__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: Erik R.
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183752969.373369.92040@r34g2000hsd.googlegroups.com>
Excellent!  That is exactly the kind of shift in perspective that I
needed explained to me.  Thank you!

I'm assuming that writing a function instead of a method would compile
whether or not the objects you passed to it implemented the
interface.  From my "strongly typed" background, my initial thought is
that it seems error prone to not allow for such verification at
compile-time, but perhaps in practice it's no big deal.

It's going to take some practice to stop thinking in Java...

Erik

On Jul 6, 9:59 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> "Erik R." <·············@gmail.com> writes:
> > What I want to write is a function that doesn't care what type of
> > object is passed to it, as long as it extends both DbObject and
> > SelfParenting.  Like so:
> > [...]
> > Does this make more sense?  It sounds like methods must match on
> > specific types, and can't do so on two general superclasses.  Please
> > tell me I'm wrong?
>
> Yes, method dispatching is used to select a method in function of the
> type of the arguments.  Of course, since T is a supertype of all
> types, you can always write a method that could be selected for
> undiscriminated types, but this is not the question.
>
> You want to write a function tht doesn't care what type is passed to
> it.  So you don't need a method.  Just define a function.   Now of
> course your function will expect the object to extend both db-object
> and self-parenting classes.  No problem with that.  But you have to
> ask yourself what in means, in the scope of a dynamically typed
> programming language like lisp.  What does it mean for an object to be
> an instance of such or such classes, in the context of your function?
> Nothing more than that some "interface" to this object is available to
> your function, that is, you can call some functions with this object
> as argument, and something meaningful happens.
>
> Let's take a simple example: you want to write a function that doesn't
> care what type of object is passed to it, as long as it implements the
> ELT interface where an item in the object can be selected by integer
> index.
>
> (defun f (obj)
>   (list (elt obj 0) (elt obj 2)))
>
> And surprise! This function can be called on vectors, strings and lists:
>
> (values (f "abcdef") (f #(1 2 3 4 5)) (f '(:one :two :three :four)))
> --> (#\a #\c)
>     (1 3)
>     (:ONE :THREE)
>
> So, what does it mean for an object to be both a db-object and a
> self-parenting?  Perhaps that the functions fetch, store, parent,
> children, and depth can be called with this object.  Why should your
> function care about the exact data type of the object, as long as
> these functions can be applied on it?  Just write your function and
> forget about these irrelevant details.
>
> (defun f (object)
>   (fetch object)
>   (parent object)
>   (children object)
>   (store object)
>   (depth object))
>
> If you try to call it on an object that doesn't implement this
> "interface", say: (f 42), somebody will signal an error.  If the
> client really want to call f with 42, it only has to implement the
> "interface":
>
> (defmethod fetch    ((self integer)) self)
> (defmethod store    ((self integer)) (print self))
> (defmethod children ((self integer)) (factorize self))
> (defmethod parent   ((self integer)) 1)
> (defmethod depth    ((self integer)) (log self))
>
> Et voil�!  Now you can call (f 42).
>
> --
> __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: ··············@gmail.com
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183773040.802473.256240@c77g2000hse.googlegroups.com>
> It's going to take some practice to stop thinking in Java...

Maybe you need a bit more time programming in Java to stop thinking in
it.  Personally I found myself making my interfaces as small as
possible, ideally a single method.  Then I realised that I wanted
functions, not interfaces.  Java doesn't support that properly -
higher order functions need emulating, they're not natively
accessible.  Knowing many of Java's limitations made me more able to
approach Lisp without emulating Java in it.
From: Tim Bradshaw
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183816751.227800.37900@n60g2000hse.googlegroups.com>
On Jul 6, 9:16 pm, "Erik R." <·············@gmail.com> wrote:

>
> It's going to take some practice to stop thinking in Java...
>

Although that's true in general, I think that this is a case where it
is reasonably clumsy to express what you want in CLOS.  There are
three approaches:

1. Just relax, don't specialise at all, and assume that the thing
you've got implements what you need: you'll find out if it doesn't.
This is really the traditional Lisp approach, but it sucks because
it's not apparent to anyone reading the code what assumptions you're
making unless you have some comment about it, or they read the entire
thing very carefully.

2. Interpose a class which mixes the classes you are interested in,
and specialise on that.  This sucks because it means that anyone who
passes something which *also* mixes the classes you are interested in
but does not inherit from your mixin class will lose.

3. The same-argument-twice trick.  This is neat, but kind of a hack.

Really whst you want in CLOS (as someone else said) is specializers
that let you express what you're after directly.

However all is not lost: this is, after all, Lisp.  There are two
solutions I can see:

1. Add such specializers to CLOS.  That's probably not that hard given
a fully-fledged MOP.

2. Well, this *is* Lisp.  Write a version of DEFMETHOD which supports
a new syntax:

(defmethod foo ((x (and a b))) ...)
->
(cl:defmethod foo-and-2 ((x a) (y b))
  (assert (eql x y))
  ...))

or something like that.  In other words, you can implement this thing
with macros.

--tim
From: Jon Harrop
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <46902196$0$8724$ed2619ec@ptn-nntp-reader02.plus.net>
Erik R. wrote:
> I'm assuming that writing a function instead of a method would compile
> whether or not the objects you passed to it implemented the
> interface.  From my "strongly typed" background, my initial thought is
> that it seems error prone to not allow for such verification at
> compile-time, but perhaps in practice it's no big deal.

It is a big deal and most modern functional programming languages (e.g.
OCaml, Haskell, F#) solve this problem with sophisticated static type
systems.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
The OCaml Journal
http://www.ffconsultancy.com/products/ocaml_journal/?usenet
From: Pascal Bourguignon
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <87ir8xs8k0.fsf@thalassa.lan.informatimago.com>
·············@gmail.com writes:
> You can achieve the same behaviour of your Java example using multiple
> inheritance:
>
> (defclass my-comparable-base-class (my-base-class comparable) (...))
>
> and thus
>
> (defmethod do-some-comparison ((obj my-comparable-base-class))
>   ;; here obj is guaranteed to subclass both my-base-class and
> comparable
>   )
>
> I hope this answers your question.

With the caveat that:

(defclass m1 () ())
(defclass m2 () ())
(defclass a (m1 m2) ())
(defclass b (m1 m2) ())
(and (not (subtypep 'a 'b)) (not (subtypep 'b 'a))) --> T

therefore:

(defmethod m ((self a)) (print 'Hi))
(m (make-instance 'b))
--> *** - NO-APPLICABLE-METHOD: When calling #<STANDARD-GENERIC-FUNCTION M> 
          with arguments (#<B #x208A34DE>), no method is applicable.


So perhaps the best answer would be:

(defun m (object)
  (cond ((and (typep object 'm1) (typep object 'm2))
          (do-stuff object))
        #| possibly add here other cases |#
        (t
          (error "expected an instance of both m1 and m2"))))


-- 
__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: ·············@gmail.com
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183746631.049985.316070@k79g2000hse.googlegroups.com>
On 6 Lug, 20:15, Pascal Bourguignon <····@informatimago.com> wrote:
> ·············@gmail.com writes:
> > You can achieve the same behaviour of your Java example using multiple
> > inheritance:
>
> > (defclass my-comparable-base-class (my-base-class comparable) (...))
>
> > and thus
>
> > (defmethod do-some-comparison ((obj my-comparable-base-class))
> >   ;; here obj is guaranteed to subclass both my-base-class and
> > comparable
> >   )
>
> > I hope this answers your question.
>
> With the caveat that:
>
> (defclass m1 () ())
> (defclass m2 () ())
> (defclass a (m1 m2) ())
> (defclass b (m1 m2) ())
> (and (not (subtypep 'a 'b)) (not (subtypep 'b 'a))) --> T

I had not thought about that. My answer was not completely wrong --
the parameter passed to my method is guaranteed to subclass both my-
base-class and comparable. However, it does NOT guarantee that the
method will be applicable to every class subclassing my-base-class and
comparable, and probably this is not what the OP wanted - in fact it
is not the correct translation from Java.

> So perhaps the best answer would be:
>
> (defun m (object)
>   (cond ((and (typep object 'm1) (typep object 'm2))
>           (do-stuff object))
>         #| possibly add here other cases |#
>         (t
>           (error "expected an instance of both m1 and m2"))))
>

Of course. Even from simple examples like this you can distinguish
gurus like Pascal from lusers like me :)
From: André Thieme
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <f6m4ba$4t3$1@registered.motzarella.org>
Pascal Bourguignon schrieb:
> ·············@gmail.com writes:
>> You can achieve the same behaviour of your Java example using multiple
>> inheritance:
>>
>> (defclass my-comparable-base-class (my-base-class comparable) (...))
>>
>> and thus
>>
>> (defmethod do-some-comparison ((obj my-comparable-base-class))
>>   ;; here obj is guaranteed to subclass both my-base-class and
>> comparable
>>   )
>>
>> I hope this answers your question.
> 
> With the caveat that:
> 
> (defclass m1 () ())
> (defclass m2 () ())
> (defclass a (m1 m2) ())
> (defclass b (m1 m2) ())
> (and (not (subtypep 'a 'b)) (not (subtypep 'b 'a))) --> T
> 
> therefore:
> 
> (defmethod m ((self a)) (print 'Hi))
> (m (make-instance 'b))
> --> *** - NO-APPLICABLE-METHOD: When calling #<STANDARD-GENERIC-FUNCTION M> 
>           with arguments (#<B #x208A34DE>), no method is applicable.
> 
> 
> So perhaps the best answer would be:
> 
> (defun m (object)
>   (cond ((and (typep object 'm1) (typep object 'm2))
>           (do-stuff object))
>         #| possibly add here other cases |#
>         (t
>           (error "expected an instance of both m1 and m2"))))

Nah, this is too ugly.
The idea of multimethods was to not have things like that, were one has
to manually dispatch things.

Multimethods provide a subset of functionality of pattern matching.
So better shadow defmethod and on top of that offer one that uses a
PM under the hood and still supports the standard syntax. Then you have
all the flexibility you want.
From: jayessay
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <m3d4z5v5oz.fsf@sirius.goldenthreadtech.com>
"Erik R." <·············@gmail.com> writes:

> Am I making myself clear?

Not particularly.  What do you actually want to do?  Since CLOS has
full multiple inheritance and multiple dispatch it would seem what you
want here is a simple application thereof.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Dan Bensen
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <f6lupo$lcc$1@wildfire.prairienet.org>
Erik R. wrote:
 > can I defmethod a method that requires its argument
 > to be a subclass of more than one class?
 > For instance, in Java, I could do:
 > public static <T extends MyBaseClass & Comparable<T>>

 > Can you specify more than one?  Like:
 > (defmethod do-some-comparison ((obj (my-base-class comparable)))

jayessay wrote:
 > "Erik R." <·············@gmail.com> writes:
 >> Am I making myself clear?
 > Not particularly.  What do you actually want to do?

I think the OP wants something like
   `(and my-base-class (satisfies comparable))

-- 
Dan
www.prairienet.org/~dsb/
From: jayessay
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <m38x9tv15a.fsf@sirius.goldenthreadtech.com>
Dan Bensen <··········@cyberspace.net> writes:

> jayessay wrote:
>  > "Erik R." <·············@gmail.com> writes:
>  >> Am I making myself clear?
>  > Not particularly.  What do you actually want to do?
> 
> I think the OP wants something like
>    `(and my-base-class (satisfies comparable))

I was asking what he actually wants to do/achieve given his problem.
I suppose it could be that his "problem" is simply how do I write Java
in Lisp...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Rainer Joswig
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <2007070620504816807-joswig@lispde>
On 2007-07-06 20:26:57 +0200, jayessay <······@foo.com> said:

> Dan Bensen <··········@cyberspace.net> writes:
> 
>> jayessay wrote:
>>> "Erik R." <·············@gmail.com> writes:
>>>> Am I making myself clear?
>>> Not particularly.  What do you actually want to do?
>> 
>> I think the OP wants something like
>> `(and my-base-class (satisfies comparable))
> 
> I was asking what he actually wants to do/achieve given his problem.
> I suppose it could be that his "problem" is simply how do I write Java
> in Lisp...
> 
> 
> /Jon

I see an 'unlearning Java' thread coming... ;-)

-- 
http://lispm.dyndns.org/
From: Pascal Costanza
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <5f7dstF3a7opmU1@mid.individual.net>
Erik R. wrote:
> Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
> of generics.  Here's my question, can I defmethod a method that
> requires its argument to be a subclass of more than one class? 

No, we're not so much into static typing over here. ;)

Could be an interesting extension of CLOS though.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Paul Khuong
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <1183748661.846770.259320@g4g2000hsf.googlegroups.com>
On Jul 6, 1:53 pm, Pascal Costanza <····@p-cos.net> wrote:
> Erik R. wrote:
> > Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
> > of generics.  Here's my question, can I defmethod a method that
> > requires its argument to be a subclass of more than one class?
>
> No, we're not so much into static typing over here. ;)
>
> Could be an interesting extension of CLOS though.

Maybe a conjunction specialiser and mixins for properties (like
Comparable)?

Paul Khuong
From: Pascal Costanza
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <5f97apF3b7slqU1@mid.individual.net>
Paul Khuong wrote:
> On Jul 6, 1:53 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Erik R. wrote:
>>> Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
>>> of generics.  Here's my question, can I defmethod a method that
>>> requires its argument to be a subclass of more than one class?
>> No, we're not so much into static typing over here. ;)
>>
>> Could be an interesting extension of CLOS though.
> 
> Maybe a conjunction specialiser and mixins for properties (like
> Comparable)?

Mixins for properties are already possible. They are just empty classes.

(defclass comparable () ())

You can mix such a class into any other class, define methods on it and 
test whether a particular object is an instance of that mixin.

Conjunction specializers would be new, indeed. There are two papers at 
this year's European Lisp Workshop discussing how a MOP can be used to 
add new kinds of specializers - this could be one application thereof.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Alex Mizrahi
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <468e8922$0$90268$14726298@news.sunsite.dk>
(message (Hello 'Erik)
(you :wrote  :on '(Fri, 06 Jul 2007 09:29:53 -0700))
(

 ER> Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
 ER> of generics.  Here's my question, can I defmethod a method that
 ER> requires its argument to be a subclass of more than one class?  For
 ER> instance, in Java, I could do:

 ER> public static <T extends MyBaseClass & Comparable<T>> boolean
 ER> doSomeComparison(T obj)
 ER> {
 ER>   // here, i'm guaranteed that my obj variable both extends
 ER> MyBaseClass AND implements Comparable.
 ER> }

generic functions are not used for guarantees but merely for dispatch.
actually in dynamic language guarantees have somewhat different sense, and 
also methods are not attached to classes, so there are no interfaces like 
Comparable at all.

so, if you want guarantee, you can add a declaration or an assertion.

but actually you can just do no checks and use compare function as if it was 
comparable. if it is not, type error will be signaled (kinda 
no-applicable-method) -- note that it's exactly same behaviour as you'd 
achieve with generic function doing that check, so, as you see, it's 
meaningless, you just get an exception a bit later..

but if you need that for dispatch (have separate code for non-comparable), 
you can either use two generic functions -- one will dispatch on 
MyBaseClass, another on Comparable. or you can do some odd trick, like have 
two parameters and pass object into two of them:

(defmethod choff ((x my-base-class) (dummy comparable))
  ;;do what you'd like to if it was comparable
)

(defmethod choff ((x my-base-class) (dummy object))
    ;;handle non-comparable case
)

handling that directly would be an interesting extension to CLOS, as Pascal 
have wrote, but it was not included into standard because it has little 
application in Common Lisp.

(by the way, note that it's possible to express this constraint in Common 
Lisp as type -- see DEFTYPE, for example, but DEFMETHOD accepts not types 
but classes. check can be done with DECLARE, OTOH).

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"scorn") 
From: Jon Harrop
Subject: Re: Generics in Lisp?
Date: 
Message-ID: <469021ba$0$8724$ed2619ec@ptn-nntp-reader02.plus.net>
Erik R. wrote:
> Hi, I'm new to Lisp, coming from Java 1.5, where I've made heavy use
> of generics.  Here's my question, can I defmethod a method that
> requires its argument to be a subclass of more than one class?

Lisp does not guarantee that such checks are done statically. However, you
are most likely using an object oriented style without good reason. Try
writing in a functional style.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
The OCaml Journal
http://www.ffconsultancy.com/products/ocaml_journal/?usenet