Eliminating assignments and variable syntax (accessors)

Alan Lovejoy sourcery at pacbell.net
Wed Aug 4 06:57:45 UTC 1999


> ** 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!

> 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.

--Alan





More information about the Squeak-dev mailing list