I have just finished up reading the chapters on OOP from Practical Common Lisp, and was taken by surprise by the Common Lisp Object System (CLOS).
Before I go into details I should explain my background with OOP. The only Object Oriented Programming I have personally done is in C++. As such, I learned OOP from the C++ perspective, and was not aware that this is not the only way to do OOP. Apparently the C++ way was not really what was intended when the ideas of OOP first appeared. The CLOS provides a different interpretation of the concept, which frankly I like (at least in theory).
Probably the biggest difference between CLOS and C++ is that while in C++ your object has data and functions within it, in the CLOS your functions are completely seperate from your objects. In a class you do not define functions, but rather an object is pretty much just a collection of data. The way functions are handled is that you create a generic function and define a specialized method of the generic function for the appropriate class or classes. I quite like this because it seems like a more faithful model. Many interesting functions of objects are ones in which two or more objects are interacting with each other in some way. Because the methods of this system belong outside the definitions of classes, we can easily have methods that belong to multiple objects.
When it comes to defining the classes themselves, we have many other interesting features. In the CLOS there is only one kind of member, public members. These are called slots. As stated before, slots do not hold methods, they are only a place which can hold a value. The CLOS provides three basic ways of handling object initialization. When an object is created, we can pass arguments into it by using :initarg. If we want a slot to have a default value, we can set it with :initform. When the object is created, the primary method initialize-instance sets it up with the supplied :initarg and :initform options. We can define an auxiliary method of initialize-instance with :after that allows us to set slots based on value of other slots within the object. This is essentially like defining a constructor for an object in C++.
It would quickly become tedious to define setters/getters for the slots of our classes. Especially considering that we will want them to be methods of generic functions if we want to have them for inherited classes. Luckily CLOS provides special options to handle this. :reader, :writer, and :accessor allow for a very convenient way to provide interfacing to your class. With-slots and with-accessors are two macros that provide direct access to slots and a shorthand for accessors respectively. We also have class allocated slots, which is where all instances of the class point to a single shared slot. This is useful to save space, by pooling common resources. There is also a fairly complicated system of inheritance.
Looking at all these features, it seems that Common Lisp is certainly not lacking in regards to OOP. However one small drawback of the CLOS is that you don’t really have encapsulated data. This irks me a bit, but I think I will be able to overlook it.
So far I am happy with Common Lisp. I am looking forward to finishing this book and getting started working on some projects with the language.