Re: To CLOS or not to CLOS?

Pascal Costanza <[email protected]>
Newsgroups gmane.comp.lang.lightweight
Message-ID <[email protected]>
On 20 Feb 2007, at 05:16, [email protected] wrote:

>> On Sun, 2007-02-18 at 18:22 -0600, Paul F. Dietz wrote:
>> Over the past couple years, I have really learned to appreciate  
>> CLOS...
>
>     Paul Graham mentioned at one point that after years of LISP
> programming he never *once* used CLOS to get the job done.  Perhaps
> because LISP's pre-OO parts are so powerful you can do a lot already
> without resorting to objects.

If I understand Paul Graham correctly, he doesn't like OOP in  
general, so his criticism is not specifically about CLOS, but he uses  
CLOS more as an example to make a few points.

> But obviously CLOS has it's fans as
> well.  If you are a Common LISP user, what do you like or not like
> about CLOS?  For example, is the generic function approach the best
> way to do OO, or does it have some drawbacks compared to the common
> object-dispatched system?

CLOS is pretty much the most complete object system you can get.  
There are only a few things that come to my mind that CLOS doesn't do  
well:

- It doesn't provide strong encapsulation: Methods are defined  
outside classes (to make multiple dispatch work and, more  
specifically, to integrate method dispatch better with functional  
programming). So if a method needs access to some state that an  
object provides, you need to provide that state to that method. (I  
don't think that encapsulation belongs in an object system.  
Encapsulation should rather be part of a module/package system, and  
then there is no real issue here.)

- CLOS doesn't provide straightforward means to scope classes,  
generic functions and methods to lexical environments. This would  
provide functionality somewhat similar to classboxes. This is no  
principle issue, though, it's just not implemented.

- With CLOS, it's not straightforward to implement object wrappers,  
i.e., methods/functions that can intercept all messages sent to  
specific objects (for example like the "message not understood"  
machinery in Smalltalk). (However, I don't think that's a strong  
limitation. All object wrappers that I have seen filter out the  
messages that they are actually interested in and leave out others.)

- CLOS doesn't provide strong static type checking. But that's a  
topic of its own... ;-)


The reasons why I like CLOS are essentially this:

- CLOS provides a very smooth integration with functional  
programming. There is no syntactical difference between a function  
call and a generic function call. From a client's perspective, there  
is even no semantical difference between function and generic  
functions - you just invoke them. You can also easily pass around  
generic functions as first-class values, just like any other  
function. This smooth integration is very interesting for bottom-up  
software evolution: You can start out your code with plain functions,  
grow it to a certain level, and then decide to switch to generic  
functions / OOP without breaking any client.

- CLOS's combination of class specializers, eql specializers (methods  
defined on single objects), and method combinations  
(like :before/:after/:around methods) provides a very powerful way to  
express partial behavior of a generic function. You can get pretty  
close to a very declarative programming style this way.

- CLOS's class system provides, among other things, multiple  
inheritance and the ability to redefine class hierarchies at  
development time / runtime. Such redefinitions have an effect on  
existing instances and generic functions, so this allows for very  
straightforward ways to evolve your system while it's running. For  
example, you can easily add mixins to existing classes / objects  
without interrupting a running program.

- CLOS is highly configurable. Almost each aspect of CLOS can be  
changed by providing user-defined method combinations, and more  
specifically, user-defined metaclasses for classes, generic  
functions, slots and methods. Since CLOS already provides a rather  
complete coverage of possible functionality, it's relatively  
straightforward to carve out your own domain-specific object systems  
with adaptations that you need for your specific use cases.

- On top of that, if you design your metaclasses in the right way,  
your own adaptations of the object system can take advantage of the  
fact that CLOS implementations themselves are highly efficient.  
That's probably one of strongest advantages over building your own  
domain-specific object system from scratch: Implementing an OOP  
language in, say, Scheme, plain Lisp, or some other non-OOP language,  
is indeed quite easy - but doing this such that the resulting system  
yields good performance characteristics is very hard. (For example,  
think of all the optimizations advanced OOP implementations do for  
you, like in the JVM, Self or Strongtalk - you don't want to put such  
effort into your own object systems.) With CLOS metaclasses, you  
basically get the same advantage here that OOP gives you at the base  
level: You can more easily reuse what's already there, including its  
characteristics wrt functionality, performance, etc.


These are just the reasons why I like CLOS. For another overview from  
a slightly different perspective, see http://www.lisp.org/table/ 
objects.htm

For a rationale of CLOS, see the excellent paper "CLOS in Context:  
The Shape of the Design Space" at http://www.dreamsongs.com/CLOS.html


Pascal

-- 
Pascal Costanza, mailto:[email protected], http://p-cos.net
Vrije Universiteit Brussel, Programming Technology Lab
Pleinlaan 2, B-1050 Brussel, Belgium
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.