Constructors (was: RE: About KCP and automatic initialize)

Richard A. O'Keefe ok at cs.otago.ac.nz
Thu Sep 18 02:13:08 UTC 2003


Daniel Vainsencher <danielv at netvision.net.il> wrote:
	I'll tell you what worries me. The metaphor for "what code is" in a
	system is IMO critical for people to feel at home in it. In C its a
	bunch of files that get transformed. Awkward, but clear. In Scheme,
	AFAICT, its a bunch of definitions that get interpreted and executed in
	terms of one another (one can define new syntax for use in another). In
	Smalltalk, code is a material that the environment executes and exposes
	for shaping by the user. Code is always defined or modified by the user,
	though some tools help him do so. This is a powerful model, because it
	is pretty interactive and transparent. IMO, making parts of it derived
	breaks some important assumptions in that simplicity.
	
I think we need to remind ourselves what Squeak is, here.
Squeak is an *open* system, where everything that the IDE needs is
accessible to a program.
So derived methods are *already* possible.
(One of Andreas Raab's messages included code that constructed a whole
heap of classes, for example.)
What we don't have is tools that can be told about the derivation.

So the "assumptions in that simplicity" are unfounded; Squeak is a little
bit pregnant.  You can't abort that pregnancy without killing off the tools
or the openness.  Better to bring it to birth.

	1.  A class-side DNU which looks up the message on the instance
	side, and if an implementation is found in the initialize
	protocol, creates a method that calls it.

Ooh, nice one!  The same effect as Andreas Raab's proposal, but without
any syntax change at all.  BUT, it's making a derived method.

	2.  A menu option for methods "make initializer" that generates
	the stub described above on the class side.

Again, this is making a derived method.  Either the system is revised to
keep track of the derivation, so that it can be repeated when the base
method is revised, or the two methods can get out of synchrony (add an
argument to the instance-side method and the class-side method doesn't
get to hear about it).  A derived method is a derived method, whether it's
done by special syntax that the compiler recognises, or by a DNU that forges
some text and hands it to the compiler, or by a menu option in a browser.

In some ways I like option 2 the best, but it has a disadvantage:
when a human is looking at the instance-side method, s/he can't tell
that it's an initializer.  Perhaps if the menu option were only available
for methods in an 'instance creation' category, ah, I'm onto something here.

Hook it to the method category.
If (theClass includesBehavior: Behavior) not, then
  If you create a method in the 'instance creation' category on the instance
    side, automatically create the class-side hook (in the 'instance creation'
    category) unless it already exists.
  If you move a method into the 'instance creation' category on the instance
    side, automatically create the class-side hook (in the 'instance creation'
    category) unless it already exists.
  If you move a method _out_ of that category,
    automatically remove the class-side hook provided it exists and is just
    a call to the method being recategorised.
  If you delete a method from that category,
    automatically remove the class-side hook provided it exists and is just
    a call to the method being deleted.

How compatible would this be with the existing system?

    Smalltalk allClasses select: [:each |
        each organization categories includes: #'instance creation']
==> OrderedCollection(Behavior Environment InterpreterProxy
                      Metaclass UUIDGenerator)

MetaClass is a descendant of Behavior, so that's already taken care of.
That leaves just Environment, InterpreterProxy, and UUIDGenerator.

Looking at UUIDGenerator, *all* of the methods in the category
'instance creation' are in fact initialisation methods.  If that
category hasn't already been renamed to 'initalization' or
'initialize/release', it should be for 3.6final or at least 3.7alpha.

Looking at Environment,
    #setName:outerEnvt:, #setName:inOuterEnvt:
are clearly initialisation methods, not instance creation methods.
    #makeSubEnvironmentNamed: 
does create a new environment and return it.  The only senders I can
find do "Smalltalk makeSubEnvironmentNamed: ...".  Some other message
category might be more appropriate for this method, 'making children',
perhaps.

Looking at InterpreterProxy,

    makePointWithxValue: xValue yValue: yValue
	(xValue class == SmallInteger and: [yValue class == SmallInteger])
	    ifFalse: [self error: 'Not SmallInteger objects'].
	^xValue at yValue

should clearly be in Point:

    Point class>>
    smallX: xSmall smallY: ySmall
	xSmall class == SmallInteger
	    ifFalse: [self error: 'x value not a SmallInteger'].
	ySmall class == SmallInteger
	    ifFalse: [self error: 'y value not a SmallInteger'].
	^self x: xSmall y: ySmall

Not only is "Point smallX: 27 smallY: 42" a more intention-revealing name,
it would be in the right class.

Continuing to look at InterpreterProxy,
why is #popRemappableOop in 'instance creation' when it doesn't create any
instance of anything, and why is #pushRemappableOop in 'instance creation'
when it doesn't create any instance of anything?

#instantiateClass:indexableSize: _is_ a method for creating instances,
but not of the class it belongs to.  It's called from a bunch of plugins,
so there's probably some Slang-related reason for doing this.

#clone: is again a bona fide instance creator, but why would you call
interpreterProxy clone: oop   rather than oop clone?  Again, it's
probably something to do with Slang (B3DTransformerPlugin uses it).

Nothing about InterpreterProxy would break if that message category
were renamed, not that beginners should be messing with it anyway.

At the price of a method category renaming that ought to be done anyway,
and two method category renamings that won't hurt, this rule
"creating, moving, or deleting 'instance creation' methods in classes
that don't descend from Behavior implies corresponding changes to their
metaclass" seems to fit reasonably well.



More information about the Squeak-dev mailing list