[comp.lang.clos] Beefs about CLOS

kramer@ai.toronto.edu ("Bryan M. Kramer") (03/14/91)

I have just begun using CLOS after having had considerable
experience in LOOPS and C++. There are two things about the
language I find really annoying. I don't imagine that
they can change, but I felt like getting them off my
chest. Since I'm fairly new to CLOS, maybe I'm misinterpreting
the spec.

1) Congruent lambda lists for generic functions. The
main problem with this is that it seems to go against
modularity in that the designer of a class has to make
sure that no method names conflict with method names for
other classes. For example, suppose one is working in
an environment that contains graphical interface package
with a class hierarchy for graphical objects that has
a method called LAYOUT. Suppose now, that you are writing
a system for chip design and decide the best name for
a certain method here is also LAYOUT. Suddenly you have
a name conflict that you wouldn't have had in LOOPS or
C++.

A second problem with congruency arises when one would 
like to write two different methods to perform the same
function ... here one would like the same method name
but different lambda lists. For example, a graph
manager object might have two PLOT methods, one which
accepts an array of x-y pairs and another which accepts
a list of pairs ((x1 y1) (x2 y2) ...) as an argument.

It also seems common to need to add parameters as one
specializes methods ... this is practically a very useful
capability although I can see theoretical arguments against
it.

Note that &optional or &keyword parameters don't fit the
bill because one cannot specialize methods based on these
parameters.

2) Custom arguments to INITIALIZE methods. I find that frequently
that the values I would like to pass to make-instance to
initialize an object are not values that I would like to
store in slots. An artificial example here is a system that
stores locations in polar coordinates but that is naturally
initialized by Cartesian coordinates. Where I would want
to write
[a]    (make-instance 'position :x x :y y)
I have to write
[b]    (let ((new (make-instance 'position)))
       (setup new x y)
       new
       )
The biggest problem is that I run into 1) above, i.e.
lambda list congruency. I have to invent a new name for
SETUP for every class for which this is necessary. Being
allowed 2) without 1) would still be a problem because
it would be nice to also allow the initialize method to
use cartesian coordinates if necessary.



 Bryan M. Kramer	- 416-978-7330 -
 Department of Computer Science, University of Toronto
 Toronto, ON      M5S 1A4

barmar@think.com (Barry Margolin) (03/14/91)

In article <91Mar13.134622est.133188@wotan.ai.toronto.edu> kramer@ai.toronto.edu ("Bryan M. Kramer") writes:
>1) Congruent lambda lists for generic functions. The
>main problem with this is that it seems to go against
>modularity in that the designer of a class has to make
>sure that no method names conflict with method names for
>other classes. For example, suppose one is working in
>an environment that contains graphical interface package
>with a class hierarchy for graphical objects that has
>a method called LAYOUT. Suppose now, that you are writing
>a system for chip design and decide the best name for
>a certain method here is also LAYOUT. Suddenly you have
>a name conflict that you wouldn't have had in LOOPS or
>C++.

Packages are intended to solve the problem of name conflicts across
unrelated programs.  The signature of GRAPHICS:LAYOUT doesn't have to
match the signature of CAD:LAYOUT.

Flavors also doesn't require congruent lambda lists.  The most annoying
feature of systems that don't make this requirement is that the programming
environment can't assist users.  In CLOS, one can write

	(arglist 'gen-func-name)

(on systems that have an ARGLIST function).

>A second problem with congruency arises when one would 
>like to write two different methods to perform the same
>function ... here one would like the same method name
>but different lambda lists. For example, a graph
>manager object might have two PLOT methods, one which
>accepts an array of x-y pairs and another which accepts
>a list of pairs ((x1 y1) (x2 y2) ...) as an argument.

I don't understand the problem here.  This sounds like:

(defmethod plot ((g graph) (points array))
  ...)
(defmethod plot ((g graph) (points cons))
  ...)
(defmethod plot ((g graph) (points null))
  ...)

>It also seems common to need to add parameters as one
>specializes methods ... this is practically a very useful
>capability although I can see theoretical arguments against
>it.
>
>Note that &optional or &keyword parameters don't fit the
>bill because one cannot specialize methods based on these
>parameters.

If the additional parameters are only useful when the earlier arguments are
of a particular class, the choice of method can be based only on the
earlier arguments, so you don't need to specialize on these.

>2) Custom arguments to INITIALIZE methods. I find that frequently
>that the values I would like to pass to make-instance to
>initialize an object are not values that I would like to
>store in slots.

Define an after-method on MAKE-INSTANCE.  Any keywords that this method
accepts are valid in a call to MAKE-INSTANCE of that class.  As you
mentioned, these arguments can't be specialized on, but you can call other
generic functions within the method that do.

--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

kramer@ai.toronto.edu ("Bryan M. Kramer") (03/14/91)

The examples I chose in my original article did not fully
illustrate my beefs. When I complained about argument
list congruency, my concern was that the number of required
parameters have to be the same. There is of course, no
conflict in the layout example if the methods are defined
as follows:

(defmethod layout ((r region)) ...)

and 

(defmethod layout ((c chip)) ...).


My plot example was completely irrelevant to the point
I was making, since one definitel can do

(defmethod plot ((x cons)) ...)
and
(defmethod plot ((x vector)) ...)

So in summary, my complaint is that the number of
number of required parameters has to be the same.
I apologize for the lack of clarity in my original
article.

 Bryan M. Kramer	- 416-978-7330 -
 Department of Computer Science, University of Toronto
 Toronto, ON      M5S 1A4

rshapiro@arris.com (Richard Shapiro) (03/14/91)

In article <91Mar13.134622est.133188@wotan.ai.toronto.edu> kramer@ai.toronto.edu ("Bryan M. Kramer") writes:
>1) Congruent lambda lists for generic functions. The
>main problem with this is that it seems to go against
>modularity in that the designer of a class has to make
>sure that no method names conflict with method names for
>other classes.


This seems like *better* (more coherent) modularity to me.  If you
want to advertise a generic function as part of a modular interface,
it must have a single lambda-list. Otherwise it isn't a (single)
generic function at all. If you truly need different arglists for
different methods, then what's wrong is not CLOS but rather your
programming decision to make a single generic function out of
disparate methods.

> For example, suppose one is working in
>an environment that contains graphical interface package
>with a class hierarchy for graphical objects that has
>a method called LAYOUT. Suppose now, that you are writing
>a system for chip design and decide the best name for
>a certain method here is also LAYOUT. Suddenly you have
>a name conflict that you wouldn't have had in LOOPS or
>C++.

In this case, you should certainly be using different packages for the
two subsystems. I.e., there are actually two different generic
functions called LAYOUT, one in the GRAPHER package and one on the
DESIGNER package (package names chosen at random).


>A second problem with congruency arises when one would 
>like to write two different methods to perform the same
>function ... here one would like the same method name
>but different lambda lists. For example, a graph
>manager object might have two PLOT methods, one which
>accepts an array of x-y pairs and another which accepts
>a list of pairs ((x1 y1) (x2 y2) ...) as an argument.

I don't see the problem here. Both methods take a single argument: one
takes an array, the other takes a list. Sounds like classic CLOS to me
:) 

>It also seems common to need to add parameters as one
>specializes methods ... this is practically a very useful
>capability although I can see theoretical arguments against
>it.

As you develop a new system, you may indeed need to add new arguments
to an existing generic function (just as you might need to add new
arguments to a conventional function). In this case, you should either
add those arguments to each method; or you should decide that you no
longer have one generic function, and you rename one of them. All
sorts of things can change when you're prototyping: class definitions,
arglists, packages, etc. There's nothing special about changing the
lambda list of a generic function.

>2) Custom arguments to INITIALIZE methods. I find that frequently
>that the values I would like to pass to make-instance to
>initialize an object are not values that I would like to
>store in slots.

CLOS allows arbitrary keywords in INITIALIZE-INSTANCE methods. This
should solve your problem.