At this point in our walk through less commonly seen features of Lisp we come to the slot-value function. This is a good place to reiterate some of the differences between the way C++ and Lisp objects are handled.
In C++, a class will typically have private and public methods. The public methods form the user-facing API, while the private methods are used for internal implementation, and cannot be used by non-friend classes or functions. The same goes for private and public members, other classes or functions don’t have access to private member objects. Friends of a class are declared in the class definition, as are the public/private modifiers, so it is not possible for another function or class to manipulate the private members or methods of a class without changing the class definition itself.
In Lisp, the private/public distinction is still present, but it is not as strictly enforced. Where C++ has public and private methods on a class, Lisp has external and internal symbols on a package. In C++ one typically writes methods referred to as “getters” and “setters” for a member in a class, while a class in Lisp can have :reader, :writer, or :accessor methods for individual members.
So, I mentioned that Lisp does not enforce the private/public distinction as strictly as C++. In Lisp, it is possible to use the internal symbols of a package, one has merely to use a double colon between the package name and the symbol name, rather than the usual single colon used for external symbols. This makes it immediately obvious that the code is using symbols that are not part of the API, but means that the programmer does not have to modify the other package to cause it to export that symbol. The equivalent for accessors is slot-value. This function allows the programmer to read or modify (with setf), any named slot in an instance of a class, regardless of whether or not there are accessors associated with it.
When a programmer finds him or herself using internal symbols from packages, or most uses of slot-value, it’s a sign that some examination of the context may be required. The maintainer of the package probably feels free to modify the internal symbols of his or her package without worrying about backward compatibility, as it’s not part of the API, so other code that makes use of those internal symbols may break if the package is upgraded. Further, unlike C++, where the friends of the class are listed in the class definition, Lisp provides no similar method for the programmer changing the package to know where some code somewhere might be making use of internal symbols.
Similarly, manipulation of slots of an instance through slot-value often indicates that the programmer did not think such manipulation wise, perhaps because changes to it must accompany other changes for consistency, so a naive poking about in the innards may have unexpected results.
There are, however, some common use cases for slot-value that are expected and not suggestive of problems. The first is exactly in the case mentioned at the end of the previous paragraph. When a method changes two or more slots together, you do not want :writer methods that allow the manipulation of those slots individually. You might create :reader methods, and then use slot-value with setf to change the slots together in a single method. A second case is in setting what a C++ programmer would call a const member object. Once more, the programmer doesn’t want to create a :writer or :accessor method for the slot, to discourage others from changing it, but that slot does have to be set during instance creation. There, the use of slot-value is natural and preferred.