When I first introduced Self, I mentioned that Self is
a programming language which employs prototype-based inheritance; it does not
depend on a class-instance distinction to facilitate object-oriented
programming, but rather, it uses a prototype object from which copies are
created. The methods associated with a prototype is stored in a traits object
which is just another object storing methods that can be used on a prototype and
all its copies through a parent slot.
The trouble begins when we actually try to implement this prototype-based
inheritance system as an actual virtual machine, particularly with regards to
memory consumption. Say that I have a prototype object point with a constant
parent slot pointing to traits point and two assignable slots, x and
y. When we copy this object, we would expect to copy all three fields. But
if we scale that up, that’s so much unnecessary data being copied! For one, for
every copy of the point prototype we make, we’re copying that traits point
parent slot reference. Not to mention, because our language is dynamic, we can’t
simply treat x and y as offsets into memory, because they might be constant
or assignable (Self can’t intrinsically know). So our naive implementation would
be pretty inefficient.
Can we make this more memory-efficient? In fact, we can; we can exploit the fact
that most Self objects that are copied only ever have their assignable slots
modified. Let’s take a look at how the original developers of Self have
optimized the memory usage of the Self virtual machine.