As part of my exploration of Ruby, I attended Francis Hwang’s presentation to the New York Linux Users’ Group. One feature that caught my interest in his talk was the OpenStruct class, which lets you assign values to arbitrary “slots” within an object.
require 'ostruct' me = OpenStruct.new me.name = "Stuart Sierra" me.net_worth = -500
me.name returns “Stuart Sierra” and
me.net_worth returns -500. The clever thing about this is that nowhere did I define
net_worth as member variables or methods of a class. They just spring into being in the
OpenStruct instance as soon as I use them. This is great for developing new data structures before you’re entirely sure what slots you’ll need.
CL-USER> (defvar me) ME CL-USER> (setf (get 'me 'name) "Stuart Sierra") "Stuart Sierra" CL-USER> (get 'me 'name) "Stuart Sierra"
What I find curious is that this feature of Common Lisp is totally distinct from the object system. Object slots are not symbol properties, just as symbols are not objects (they are bound to objects). But one could make a passable prototype-based object system using just symbol properties and function closures. I think it’s one of those places that shows how Common Lisp grew from many different sources, resulting in similar but distinct ways of doing the same thing. Peter Seibel demonstrates that it can be useful to have both, by using symbol properties to store bookkeeping information needed by macros that generate new classes.