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

Defining a method on arrays of rank 2

12 views
Skip to first unread message

Erann Gat

unread,
Nov 6, 2002, 4:24:40 PM11/6/02
to

Is there a way to define a CLOS method on arrays of rank 2 (i.e.
matrices)? I tried (deftype matrix () (array t (* *)) and then (defmethod
foo ((m matrix))... but that didn't work because deftype defines a type,
not a class, and defmethod argument specificiers are required to be
classes, not types.

Thanks,
E.

Christopher C. Stacy

unread,
Nov 7, 2002, 4:54:56 AM11/7/02
to
>>>>> On Wed, 06 Nov 2002 13:24:40 -0800, Erann Gat ("Erann") writes:

Erann> Is there a way to define a CLOS method on arrays of rank 2
Erann> (i.e. matrices)? I tried (deftype matrix () (array t (* *))
Erann> and then (defmethod foo ((m matrix))... but that didn't work
Erann> because deftype defines a type, not a class, and defmethod
Erann> argument specificiers are required to be classes, not types.

Right - parameter-specializer-names are either a symbol,
which must be a class, or the list (EQL specializer-form).
CLOS doesn't let you write methods dispatched on arbitrary type specifiers.
This is a fundamental disconnect between Lisp's type system and its
class system: you can't write methods on types.

As far as I can see, the MOP won't let you change that with
specializer metaobjects, either. For one thing, you can't
hack the magical implementation of CLASS-OF nor are you
allowed to change around the metaclass BUILT-IN-TYPE.
But I'm no expert on the MOP.

I believe that this disconnect was an intentional design decision.

CLTL2 seems to this tone when discussing it:
"Many but not all of the predefined Common Lisp type specifiers have a
corresponding class with the same proper name as the type. These type
specifiers are listed in table 28-1. For example, the type array has a
corresponding class named array. No type specifier that is a list,
such as (vector double-float 100), has a corresponding class.
The form deftype does not create any classes."

Offhand, my guess is that there would be problems figuring
out the effective methods, for example on non-disjoint types.
The BUILT-IN-CLASS classes are designed for most-specific dispatching.

Dylan also has the EQL hack, calling it a "singleton type", but also
goes on to define the rules for computing the effective method of
things like union types and restricted types.

If you really wanted to do this, you could pretty easily define
your own object system layered on top of CLOS, at some cost.
Shadow DEFMETHOD with your own macro that checks all parameter
specializer names to see if any of them are either of BUILT-IN-CLASS,
or else not classes nor EQLs. Whenever you see a BUILT-IN-CLASS,
you substitute your own dispatcher function. When you see a parameter
specializer that is type that is not a class, you write a method on
the class that fills in for such things. So when CLOS does a generic
function call on a BUILT-IN-CLASS object, it runs your own dispatcher
which looks up in a registry to see if you have provided a more
specific method, using whatever rules you want to implement.
You will have to be clever about your stand-in class(es) and the
decision of when to substitute the dispatcher for a BUILT-IN-CLASS;
you need to take the existing BUILT-IN-CLASS subclass hierarchy,
or else CLOS might preempt you in some funny way. Function calling
for instances just works as always without any hacking around.

There are going to be issues about writing programs in such a system,
especially in the large. What would complex programs that took
heavy advantage of this kind of specializing wind up looking like?
I haven't followed the type-oriented language research at all,
but I am sure they must have figured out something in that area.

Barry Margolin

unread,
Nov 7, 2002, 11:04:40 AM11/7/02
to
In article <uu1itk...@dtpq.com>,

Christopher C. Stacy <cst...@dtpq.com> wrote:
>Offhand, my guess is that there would be problems figuring
>out the effective methods, for example on non-disjoint types.

I agree. Which is more specific, (array * (100 100)) or (array fixnum (*
*))? The first is more specific about the dimensions, the second is more
specific about the element type.

--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Tim Bradshaw

unread,
Nov 7, 2002, 11:15:38 AM11/7/02
to
* Barry Margolin wrote:

> I agree. Which is more specific, (array * (100 100)) or (array fixnum (*
> *))? The first is more specific about the dimensions, the second is more
> specific about the element type.

However this can be worked around by fiat - simply define the ordering
(my vote would be for elt type then dimensions). This is kind of
analogous to multimethods I think - we already need to decide whether
a method on (integer t) or one on (t symbol) is applicable to (3 foo).

A more pathological case is (array * (1 2)) vs (array * (2 1)) ... I
guess the answer would be to allow dispatch only on rank not dimension
(and presumably all arrays of differing ranks would count as disjoint
types). I can't see a use for methods specializing on arrays of rank
2 and dimensions (3 2) vs ones of rank 2 and dimension (2 3), though I
bet there is one...

--tim

Barry Margolin

unread,
Nov 7, 2002, 11:48:30 AM11/7/02
to
In article <ey3znsl...@cley.com>, Tim Bradshaw <t...@cley.com> wrote:
>* Barry Margolin wrote:
>
>> I agree. Which is more specific, (array * (100 100)) or (array fixnum (*
>> *))? The first is more specific about the dimensions, the second is more
>> specific about the element type.
>
>However this can be worked around by fiat - simply define the ordering
>(my vote would be for elt type then dimensions).

Of course we could have. But since we didn't, it becomes more obvious why
these aspects of array types don't currently fit into the class model.

And if we'd done it for arrays, it would have opened up a whole can of
worms for other complicated types, like all the different COMPLEX subtypes,
and numeric ranges (we could have an arbitrary rule for overlapping
ranges).

CLOS is mostly oriented around the STANDARD-CLASS metaclass. The ability
to specialize on built-in and structure types is best thought of as a
simple add-on. The easy cases are supported, but we didn't go to any
effort to try to integrate them completely.

The OP should probably address his issue by defining a MATRIX class with a
slot containing the actual rank-2 array.

Tim Bradshaw

unread,
Nov 7, 2002, 7:10:25 PM11/7/02
to
* Barry Margolin wrote:
> And if we'd done it for arrays, it would have opened up a whole can of
> worms for other complicated types, like all the different COMPLEX subtypes,
> and numeric ranges (we could have an arbitrary rule for overlapping
> ranges).

Yes, it would have made the spec much bigger, introduced lots of hairy
rules which no one would remember, and probably not really solved the
problem. For instance what if an implementation introduced a new
TENSOR type with analogous bells and whistles to arrays, but some
additional stuff - you'd need a whole new set of rules, and it's not
clear there's a general metarule to be had (maybe serious
CS-theory-type languages have solved all this though...).

So, really what I meant but failed to say was: it *could* be done but
whether it's worth it is another matter...

--tim

0 new messages