[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: (re)initialization revisited

Jim proposes removing some functions in the spec.  I sympathize with this as a
general goal.  But in this case I think it is misguided.  There are really four
1) initializate (make a brand new instance have the right state)
2) reinitialize (make an old instance have a "standard" starting state)
3) class-changed (make a change from one form of current instance to another)
4) update-instance-structure (make an appropriate current instance from an
outdated instance.

Because there are four concepts, there must be four entries so that users can
change what is done for each.  Collapsing concepts into a commonly named fn just
causes confusion.

For example, in doing class-changed, one can take advantage of methods on the
class-before-change; for example, changing class of p1 from an x-y-point to
rho-theta-point, one can use the methods for rho and theta defined on x-y-point.
There is no class-before-change for update-instance-structure.

Reinititializing must potentially take into account old values on slots.
Initialization never has to.  We introduced the general concept because we had
two examples in CLOS itself that require it: instances of standard-class, and
instances of standard-generic-function.  Both must take into account previous
state of the objects to be changed.


There is commonality of code in the usual case between these four concepts.  We
express that common piece as a separate function shared-initialize.   

Now the question comes up of what happens if one wants to "slightly" change the
common part.  This ability to make a slight change easily is an advertised
feature of object oriented programming.  The question comes up, what conditions
can you use to determine the slight change.

The hypothesis in our original proposal was that it was a reasonable thing to
make the slight change depend on who called the common piece.  Gregor and I
chose to enable this by making the caller name be an argument of the call.  This
supports two different mechanisms for capturing the differences

1) It allows a single method to test the value of the flag.  Or to put it
another way, it allows a case statement within the called method to determine
which code is run.  This is rather like building generic functions by using case
statements.  However, it is appropriate if most of the code is shared, and the
unshared parts are distributed through the code.

2) It supports the definition of individual methods specialized on the caller
symbol.  This is appropriate if the usual method must be completely shadowed, or
if the usual method can be surrounded by the desired special case behavior.

RPG suggested passing a functional argument.  I mistakenly though that there
would be no way of changing the functional argument in the case of class-changed
and update-instance-structure.  Dick pointed out that the way one does this is
to make a special caller that modifies the usual provided initializer functions
and calls the next method.  This is elegant provided one can easily make changes
in provided functions.  Dick suggested extending with-added-methods to allow
specification of the generic function to be changed, or later by using a special
form to mess with the incoming initializer.  

The comparison seems to be between:

RPG code:


(defmethod reinitialize-instance ((instance standard-object) 
 				  initializer &rest initargs)
  <An incredibly hairy mess>
  (apply initializer instance initargs)
  <Weirder stuff than a human can imagine>)

Now if we want to alter the behavior of shared-initialize when
called by reinitialize-instance on some more specific class than
standard-object, we do the following:

(defmethod reinitialize-instance ((instance some-class) 
 				  initializer &rest initargs)
  (initializer (mess-with-generic-function initializer))
  (apply #'call-next-method instance initializer initargs)))
Code from DGB/Gregor proposal:

(defmethod reinitialize-instance ((instance standard-object) 
 				  &rest initargs)
  <An incredibly hairy mess>
  (shared-initialize instance 'reinitialize-instance initargs)
  <Weirder stuff than a human can imagine>)

(defmethod shared-initialize ((instance some-class) 
      (caller (eql 'reinitialize-instance)) &rest initargs)
   ... whatever messing you like doing
   ... some more messing )

And there is no "with-generic-function-messed-with" macro to deal with