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


I've been reading this mail, but I haven't said anything because it's
all pretty confusing and I've been thinking.  So far I've identified
seven different relevant issues that we've been discussing here.  I'll
list them and offer my own opinion on each one.  I almost feel I shouldn't
send this, as it's still pretty confusing.  However, since it's been
a week I'm probably not doing anyone any good by keeping this to myself.

When I say "the four updating functions", I mean initialize-instance,
reinitialize-instance, class-changed, and update-instance-structure.

(1) How much should be shared among the four updating functions?  My
original complaint was that too much was shared, when reinitialize-instance
simply called initialize-instance.  Then we noticed that the other two
updating functions don't share anything, but could.  I agree that all
four should share something, but not everything (i.e. none of the four
updating functions should call one of the others).  This issue doesn't
seem to be controversial.  However, after you see what's below maybe
you'll decide that trying to share anything is hopeless and we'd be
better off duplicating some code rather than complexifying the language.

(2) What should be shared among the four updating functions?  There are
actually three different things:
  (a) the code to fill slots from initialization arguments
  (b) the code to fill slots from values of initialization forms
  (c) user-defined methods
So far the discussion does not seem to have recognized that we are talking
about three distinct things that could be shared.  The thing we are talking
about sharing is -not- simply the primary method for initialize-instance.

Now, (a) only makes sense for initialize and reinitialize, since the other
two don't have initialization arguments.  (b) doesn't make sense for
reinitialize in my opinion, and should only be done for newly added slots
for class-changed and update-instance-structure, in my opinion (see issue
4).  (c) definitely makes sense for all four, except that only initialize
and reinitialize would pass initialization arguments to the user-defined
methods.  By the way, (c) is what Barry Margolin brought up at X3J13,
so that's committee input to which we must respond.

The most straightforward thing to do here would be to provide -three-
shared functions:
  (a) initialize-slots-from-initargs instance &rest initialization-arguments
  (b) initialize-slots-from-initforms instance list-of-slots-to-consider
  (c) normalize-instance instance &rest initialization-arguments
[Never mind the names, that's issue 7]
The primary method for initialize-instance would call all three.
The primary method for reinitialize-instance would call (a) and (c).
The primary methods for class-changed and update-instance-structure would call
(b) and (c), but the second argument to (b) would be only the added local slots
and (c) would be called with only one argument.

Maybe we don't need quite this much mechanism.  For instance, (a) and (c)
could be combined if the name of (a) didn't contain the word "slots",
except that the primary method for initialize-instance ought to call (b)
between (a) and (c).  Another question is whether (a) and (b) should be
generic, and if so whether they should dispatch on the instance or on
the class.  (c) obviously is generic and dispatches on the instance.
If (a) and (b) don't have to be generic, a radical proposal that I think
should be considered would be to move them back into the implementation
dependent part of the system so that they need not be named in the standard.

I don't have a proposal to make on issue (2) at this time.  I hope I've
clarified what we're talking about, though.

(3) We've discussed several clever/kludgey ways to tweak the shared code so
it behaves differently for each of the four updating functions.  I don't
think any of them should be adopted.  I only suggested this by analogy with
slot-missing and because of the excessive sharing between initialize and
reinitialize.  If I had thought it out before sending my message I would
not have suggested it.  Once things are modularized correctly, I don't
think this extra hair would be used and I don't think we want to put it
into the language.

(4) A subtle semantic change to class-changed and update-instance-structure
has been proposed, specifically that unbound slots that are not new should
be filled from their initforms instead of being left unbound.  I'm opposed
to this change, for two reasons.  One is that I'm opposed to making any
changes in the first two chapters unless there is a good reason; I want
that part of the CLOS spec to be over and done with.  The second is that I
think an unbound slot should be treated the same as a slot with a value in
it, except when you read it.  By that rule, it's as wrong for class-changed
to bash unbound slots as it would be for it to bash slots with values in
them.  As far as I know the only reason for proposing this change was that
it appeared to simplify the sharing issue.  I don't think that would be a
good enough reason for a semantic change even if, after we understand the
sharing issue, it turns out to be true.

(5) Do we really need four different updating functions?  I think the answer
is yes, because user-defined methods could quite plausibly do different things
for each one.  The only case I'm not sure of is whether class-changed and
update-instance-structure really need to be distinguished by user-defined
methods.  Maybe they are only distinct because they take different arguments

(6) Why do the four updating functions have such inconsistent interfaces?
It makes sense for two of them to take initialization arguments and the
other two to take before & after instance states, so the real issue is why
don't class-changed and update-instance-structure take similar arguments?
I believe that is only an artifact of the way CLOS evolved; when we
abandoned the attempt to maintain a complete model of class redefinition
history, we also stopped passing a copy of the instance with its old
structure to update-instance-structure.  That was because we didn't have
any class to use for that instance.  However, just as class-changed gets a
temporary instance with potentially dynamic extent,
update-instance-structure could get a temporary instance of a temporary
class.  That would be good, because the information about what slots were
added and removed could be accessed through the normal Chapter 3 class
examination functions, instead of through special kludgey property lists,
and the values of slots could be accessed the normal way.

Although I am reluctant to change Chapters 1 and 2, I think it would be
justified to make update-instance-structure take two instances as
arguments, the same as class-changed.  We should also change the name of
update-instance-structure to make it more analogous (e.g. class-redefined).
It would probably also be okay to get rid of the distinction between
class-changed and update-instance-structure and just have one generic
function for both, although I haven't thought out the implications of that.
We should be real careful here, as we did think all this stuff out
moderately carefully and we may all have forgotten the reasons by now.

(7) What are good names for these five functions, the four updating ones
and the shared one?  I spent some time thinking about this without
satisfactory results.  Possible words for the shared operation could be
prepare, normalize, renew, reconcile, settle, adjust, adapt, setup, or
tidy.  None of those really works.  Another idea would be to call the
shared operation initialize-instance and rename the function that
make-instance calls to initialize-new-instance or instance-made.  There is
also this incoherence between class-changed ("something happened") and just
about all the other names ("do something").  I think we're still waiting
for a good idea here, and maybe we should first settle the modularity
before we pick the names.  The problem is that the existing names color
one's ideas about what the modularity should be.  We're also rapidly
approaching the day when we shouldn't change names because of the
programmer retraining problem.