[pro] When to use SLOT-VALUE...

Daniel Weinreb dlw at itasoftware.com
Wed Dec 1 14:51:33 UTC 2010


Sorry for the delay; here are my comments.

Meta-point: I prefer to work out these issues by first disregarding
speed issues, and figuring out what the best semantics is.  Then,
later, if there is real need for speedup, we can do that, but keep in
place the original intention of the code, for the benefit of future
programmers working with the code.  So, separate semantics from speed.

Hans raised what I think are two separate issues, both of them very
interesting, which I'd like to address separately, and I'll do it
in two emails since there may be two separate threads.

Using slot-value inside initialization methods.

Background: Some objects have a set of invariants.  To be more
precise, the state of the object as seen by its callers is represented
internally by more than one thing, and the state of those things must
be kept consonant with each other in order for the state seen by the
callers to make sense at the caller's level of abstraction.  Ideally,
these invariants should be carefully commented; in practice
programmers often leave them out, which is too bad.

A "consistent state" means that the invariants are true.  When there
is no method actively running that's "inside the object", i.e. at the
level of abstraction below the "consistent view", namely the ones that
*makes* things consistent, then the object must be consistent.

The methods called by the callers (1) expect to find the object in a
consistent state, and (2) must leave the object in a consistent state
when they terminate, whether they terminate normally (return) or
abruptly (signal, return, throw, etc.)

It is possible that there are :before or :after methods on the reader
or writer.  In fact, it's even possible that the primary method was
overridden, if this is a subclass.  These methods must also keep the
object in a consistent state.

Under normal circumstances, to use slot-value operates at a lower
level of abstraction.  This is, in general, dangerous, beacause
setting a slot-value could subvert the higher level's goal of keeping
the object consistent.  (If you are old enough to remember this, it's
like "peek and poke", i.e. reading and writing words in memory that
are really implementing some higher-level construct.)

However, initialize-instance is not a normal circumstance.

As Hans says, for a CLOS object, sometimes :initform is too simple,
and you need to have an initialize-instance method.  While the
instance is being initialized, in general it is not yet in its
consistent state.  The invariant says that when the object has been
created such that it's ready to be seen by callers, it must be
consistent, but not until then.  Therefore, you do NOT want to invoke
methods during the initialize-instance that will assume that the
object is consistent.  That inclues :before and :after methods (and
overridden primaries) of the accessors.

So I think Hans is right.  Not only is it OK to use slot-value here,
in fact it should be mandatory, or at least recommended, or
encouraged, or considered as the first option, or something.
(There might be times when you really know that the
method is right, although that might actually be a modularity
violation; too complicated to go into here.)

-- Dan

Hans Hübner wrote:
>
> Hi,
>
> The company I work for has a Common Lisp style guide that generally 
> disallows using SLOT-VALUE.  Instead, accessor should be used so that: 
> BEFORE and :AFTER methods are always invoked when accessing a slot.  
> Generally, I think this is a good idea when looking at classes and 
> instances from the outside.  Slots should be considered as being an 
> implementation detail, and users (i.e. client code and derived class 
> methods) should not make assumptions about how functionality is 
> implemented.
>
> Now, I often have the need for class instances that are constant in 
> some respect, i.e. some properties of the instance that are 
> implemented using slots can't directly be changed.  I often declare 
> such slots havin only a: READER in the class definition, which makes 
> the read-only nature of this slot apparent right away.
>
> Of course, such slots need to be initialized somehow. An :INITARG 
> sometimes does the trick, but it is more common that the value of such 
> slots is calculated and recalculated during the lifetime of the 
> instance, and as such the slot's value must be set.
>
> Now, from the perspective of seeing the class declaration as 
> documenting the visible behavior of instances of a class, it does not 
> seem to be proper to declare an accessor to be used in class-internal 
> code so that the slot's value can be updated.  Instead, I think that 
> it is better to use SLOT-VALUE to mess with the guts of an instance 
> from code that is part of the guts itself.
>
> Of course, one may want to argue that DEFCLASS forms should not be 
> considered to be an interface definition. Instead, one could call for 
> a series of DEFGENERIC forms to define the external interface of some 
> "module" and make class definitions be internal. From a more practical 
> perspective, though, class definitions in CL serve both as interface 
> and implementation definition, thus it seems to be appropriate using 
> the mechanisms provided by CLOS to support both uses.
>
> How do others use or avoid SLOT-VALUE? Is it frowned upon in your 
> company's or project's (verbal) style guide?
>
> Thanks for your input,
> Hans
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> pro mailing list
> pro at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/pro
>   
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/pro/attachments/20101201/a30c24b6/attachment.html>


More information about the pro mailing list