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.