Ways of new

Richard A. O'Keefe ok at cs.otago.ac.nz
Thu May 8 02:54:56 UTC 2003


The choice between
    new
        ^super new <<other stuff>>
and
    new
        ^self basicNew <<other stuff>>

is really quite simple.

First, let's note that redefining #basicNew is a big NO-NO
(just like redefining #basic<<Anything>>).  Section 3.3.2.3
of the ANSI Smalltalk standard lists "Restricted Selectors".
They are
	#ifTrue:[ifFalse:]	#to:[by:]do:
	#ifFalse:[ifTrue:]	#timesRepeat:
	#and:			#or:
	#==			#basicNew:
	#basicAt:[put:]		#basicSize
I would have expected #basicNew to be in that table, but
the standard nowhere defines or even mentions #basicNew,
although it defines "self basicNew: nnn: in section 3.4.5.
At any rate, in a Smalltalk that _has_ it, #basicNew is as
dangerous to redefine as #basicNew:.

The standard does define #new, which "return[s] a newly
created object initialized to a standard initial state", but
it's not clear to me what the standard initial state is.

So the first reason for "super new ..." is

(1) If you define a class which is not indexed, the ONLY way
    to make one in ANSI Smalltalk is "super new ...".

Suppose you have
    Object
      GrandDad
        Pater
          Fauntkin

then you can completely avoid the multiple initialisation problem thus:

    GrandDad>>new    ^super new initialiseGrandDad
    Pater   >>new    ^super new initialisePater
    Fauntkin>>new    ^super new initialiseFauntkin

If Object did ^self basicNew initialize then instead we'd have
    GrandDad>>initialize  super initialize.  more stuff 1.
    Pater   >>initialize  super initialize.  more stuff 2.
    Fauntkin>>initialize  super initialize.  more stuff 3.
BUT traditionally Object has not done this, and the ANSI Smalltalk
standard (read strictly) forbids such a change (sigh, I would have
liked that).  The "initialise<<Classname>>" approach is a little more
flexible.  If Fauntkin _doesn't_ want initialisePater, but wants its
Pater-related instance variables initialised differently, it can
simply redefine #initialisePater as well.

So the second reason for "super new initialiseMyClass" is

(2) You are using an initialisation scheme such as I've sketched above,
    and want to start by initialising the inherited instance variables
    in the way they would normally be initialised.

So when would you use "^self basicNew ...stuff..."?

(X) When you are using a Smalltalk which is documented as _having_
    #basicNew, and when your new class doesn't want the instance
    variables inherited from its parent initialised the way they
    would have been initialised by the parent.

This is typically when you are doing implementation inheritance.
Generally speaking, it's rather odd if #new doesn't returned an object
which is sufficiently initialised to be useful as it stands, so when
there's a #basicNew you have to ask "what initialisation is being
bypassed and why, and how _else_ are those instance variables being
initialised?"

Another example is
    Array2D class>>new
        ^self basicNew
which is there to override ArrayedCollection class>>new, which does a
self new: 0.  I reckon that Array2D class>>new should not be there; if
it wasn't then Array2D new would give you a useful error message instead
of a garbage object.  (There is no way to make the present result of
Array2D new useful without calling a private method.)  But the calls
to #basicNew in Array2D>>{#width:height: . #width:height:type:} seem
perfectly reasonable

Here's an odd one:

    AttributedTextStream class>>new 
      ^super basicNew initialize

Why super rather than self?

When would you use "^OtherClass basicNew ...stuff..."?
Well, I wouldn't.  In Squeak 3.2, there's

    Array class>>braceStream: nElements
      ^WriteStream basicNew braceArray: (self new: nElements)

which as far as I can see could just as well have been
      ^WriteStream on: (self new: nElements)

There's

    CanvasDecoder class>>decodeColor: string
      ...
      a < 255
        ifTrue:  [^TranslucentColor basicNew setRgb: rbg alpha: a/255.0]
        ifFalse: [^Color basicNew setRGB: rgb].

(anyone else bothered by setRgb:...setRGB:... ?)
which really should be
      ^a < 255
         ifTrue:  [TranslucentColor rgb: rgb alpha: a/255.0]
         ifFalse: [Color rgb: rgb]
with new 

      a < 255 ifTrue: [^TranslucentColor rgb: rgb alpha: a/255.0]

with new instance creation methods

    Color class>>rgb: rgb0
        ^self basicNew setRGB: rgb

    TranslucentColor class>>rgb: rgb0 alpha: a
        ^self basicNew setRgb: rgb alpha: a

This would also remove the need for
    ^TranslucentColor basicNew setRgb: rgb alpha: alphaValue
in Color>>alpha:.

Then there's

    Celeste messageMenu: aMenu shift: shifted
      ^StringHolder basicNew codePaneMenu: aMenu shifted: shifted

which doesn't really _use_ the StringHolder it creates; it just wants
to call a StringHolder method which happens not to depend on any of
the StringHolder instance variables or to refer to the object in question
in any way.

I could go on, but I think this is enough to show that "OtherClass basicNew"
is a code smell that indicates that some refactoring is needed.

There's a reason for using #basicNew which I think is a good one,
although it must still be used with care.

(Y) You have been given an abstract class where in order to ensure that
    it really _is_ treated as an abstract class, the author wrote

	AbstractClass class>>new  self subclassResponsibility.
    
    You are defining a subclass, and need to define #new.  You _can't_
    call super new.  #basicNew is the only game in town.

Looking at some of my Smalltalk written for a compiler that special-cased
#basicNew, I see that I have

(Z) When you have a concrete class whose superclasses other than object
    (if any) have no variables to initialise, so that their new method
    (if any) doesn't actually do anything, using "self basicNew" might
    be more efficient than "super new", even though they end up doing
    exactly the same thing.

In retrospect, this is probably misguided.  In that Smalltalk,
Object>>new ^self basicNew initialize, roughly speaking, so there's a
message send which I knew didn't actually do anything, so it really
_was_ a bit more efficient.  But almost certainly not enough to bother
about.  The fact that there isn't any #basicNew in ANSI Smalltalk should
have made me stop and think a bit harder.



More information about the Squeak-dev mailing list