Eliminating assignments and variable syntax (accessors)

Alan Lovejoy sourcery at pacbell.net
Wed Aug 4 08:27:09 UTC 1999


But wait!  Hold the presses!  I've got a better idea!

I want to make two ammendments:

> ** Original Sender: Alan Lovejoy <sourcery at pacbell.net>
> > ** Original Sender: Marcel Weiher <marcel at system.de>
> > > From: Alan Lovejoy <sourcery at pacbell.net>
> > > > ** Original Sender: Marcel Weiher <marcel at system.de>
> > > > Well, I guess that is the part that got sort of lost in the noise:    
> > > > If there are no accessors, the compiler compiles 'accessor/mutator'   
> > > > message sends to self as direct variable access.  Therefore, the   
> > > > object itself can access its own instance variables (and local   
> > > > variables) even if the accessors are not defined, whereas in SELF   
> > > > there is an automatic definition of accessors.
> > > >
> > > > Crucial difference.
> > >
> > > Yes, it is that.
> > >
> > > If one decides only at compile time whether "self foo" is a message  
> > > send or a variable access, one must then recompile all methods  
> > that access
> > > the iVar foo as soon as an accessor is introduced.
> > 
> > Exactly!  The difference to now is that right now I'd have to  
> > manually modify the source code of all the methods doing access,  
> > whereas with the change the system can do the recompilation  
> > automagically.
> 
> It's bad enough that all methods have to be recompiled when the
> slot definitions are changed.  Such recompilation is inelegant,
> time consuming, brittle, and requires the compiler to be present
> in order for methods to be added or removed (and also for 
> classes to be added or removed)--even when all added or changed
> methods are already precompiled.  Think of the consequences
> for moving behavior over the net!

Ammendment #1:

If an accessor method is introduced in a subclass, but does not exist
in the superclass, you CANNOT just recompile the methods in the superclass
that access the variable so that they send a message.  What message would
they send? There may be a method with such a selector just added to one of the
subclasses, but that method is not callable by instances of the superclass!  
So one would have to add such a method to the superclass "behind the scenes." 
Now, would this method show up in the browser?  Where would its
source code be found?  What if someone just removes it, since it may
not be obvious why it's there?  How would it be automatically removed
if the method in the subclass that necessitated its addition (or the whole
subclass) is later removed?

> > I never suggested this was a panacea, just that it is a *little*  
> > better than what we have now.
> > 
> > >  A worse problem
> > > is what to do when an accessor is introduced **in a subclass**.
> > > Should that change the meaning of code in a superclass, or not?
> > 
> > Again, ask yourself what happens now.  There, you've got the initial  
> > answer.
> 
> What happens now is that is that no subclass can **inadvertently** 
> change the meaning of a direct variable access or assignment simply
> by introducing an accessor or mutator method.  If the subclass decides
> that the object in the instance variable should not be subject to external
> modification, it might define an accessor that answers a copy of the
> value in the variable, thus breaking just about all existing code that
> thought it was accessing the value in the variable, not a copy thereof.
> 
> "Don't do that," you say.  That's all well and good when only one
> person ever makes changes to the code base.  What about in an
> environment where code from different sources is being merged
> dynamically, such as might happen with componets/modules/
> nameSpaces/image segments/parcels and so on and so forth?
> 
> > > Worse, suppose the accessor does lazy initialization, but there are 
> > > references to the iVar where lazy initialization would be either
> > > incorrect or at least undesirable?
> > 
> > Then you shouldn't use the basic-accessor to do the lazy initialization.
> 
> Which is a big change.  Currently, I can do lazy initialization using an
> accessor that has the same name as the variable.  This makes it transparent
> to the clients of the object whether I'm doing lazy initialization or not
> (it's none of their business, after all).
> 
> Suppose we make the following changes to Smalltalk:
> 
> 1. We introduce private methods that can only be sent to self (by either
> the defining class or any subclass).  But: the selector of a private method
> must be syntactically distinguished from public methods. For the purposes
> of discussion, let's use the convention that the selector of a private method
> must begin with an underscore, e.g., "self _doSomethingPrivate."
> 
> 2. We extend the syntax for accessing instance variables, so that an instance
> variable can be accessed by prepending an underscore (for example) to
> the name of the variable.  However, when a variable is accessed this way,
> a lookup is performed for a private method with the same name.  If none
> is found (dynamically, at run time), then the variable is accessed directly.
> Otherwise, the private method is executed instead.
> 
> So the expression "_name" would be evaluated as follows:
> 
> 1. Try to send the selector #_name.  
> 
> 2. If such a method is found, execute it and push the result.  
> 
> 3. If no such method is found, push the value of the instance variable 
> "name."
> 
> And the expression "_name := aString" would be evaluated as follows:
> 
> 1. Try to send the selector #_name: with "aString" as the argument.
> 
> 2. If such a method is found, execute it and push the result.
> 
> 3. If no such method is found, assign "aString" to the instance
> variable "name."
> 
> Just a proposal to spark discussion.  Perhaps this can be improved
> into something really interesting.

And here's the first improvement (and ammendment #2):

Each class maintains two method slots for each instance variable.
If there is no private accessor method associated with a variable, the 
accessor method slot for that variable is null.  If there is no private 
mutator method associated with a variable, the mutator slot for that
variable is null.  A non-null method slot holds the CompiledMethod
that should be executed in lieu of direct read or assignmment access
to the associated instance variable.  The slots will be updated by
the class whenever a private method with the same name as an
instance variable is added or removed, or when an instance variable
is added or removed. 
 
The virtual machine handles instance variable access (or assignment)
by first checking the accessor (or mutator) method slot associated 
with the index of the accessed (or assigned) variable.  If the slot is
null, direct instance variable access occurs.  Otherwise, the method
in the slot is called.

One could combine this with a Polymorphic Inline Cache in some 
cases (inner loops) for even better performance.

--Alan





More information about the Squeak-dev mailing list