[Newbies] Overriding methods

Ron Teitelbaum Ron at USMedRec.com
Sun Jan 20 15:54:47 UTC 2008


Hi Blake,

There are a number of ways to initialize an object.  Overridding #new is an
acceptable practice but normally this is done because you do not want a new
object created.  For example if you wanted to have only one instance of an
object you might override #new to lookup your instance and return that
instead.  

Sometimes calling #new on class is a bad idea, either this class shouldn't
have instances, or there are other instance creation methods that should be
called instead.  (We usually don't override new because of other instance
creation methods but I can understand the argument if someone did)

For example 

FishTank class>>new
	"new should not be called please use instance creations methods
instead"
	self error: 'Please use instance creation methods and not #new"
	
FishTank class>>newForGallons: numberOfGallons
	"Create a fishTank that holds numberOfGallons"
	aTank := super new.  "call super to bypass error"
	aTank numberOfGallons: numberOfGallons.
	aTank calculateGlassForGallons.
	aTank calculateTopSizeForGallons.
	aTank calculateNumberOfLightsForGallons.
	^aTank

Ok so this is kinda silly but I hope you get the idea.  This is what happens
when I make stuff up on the spot!

Ok so in most cases you can set your object up in #initalize

FishTank>>initialize
	"set up default values for aFishTank"
	self glassSides: OrderedCollection new.
	self numberOfLights: 0 copy.
	self tankShape: #rectangle

but you might want to change that setup during instance creation.

Let's move our setup code to the instance side.
FishTank>>calculateTankProperties
	"use the information provided to create a tank"
	self calculateGlassForGallons.
	self calculateTopSizeForGallons.
	self calculateNumberOfLightsForGallons.

Now change your original code to this:

FishTank class>>newForGallons: numberOfGallons
	"Create a fishTank that holds numberOfGallons"
	aTank := super new. "call super to bypass error"
	aTank numberOfGallons: numberOfGallons.
	aTank calculateTankProperties.
	^aTank

So that you can call

FishTank class>>newOctagonalTankForGallons: numberOfGallons
	"Create an Octagonal tank that holds numberOfGallons"
	aTank := super new.
	aTank shape: #octagon.
	aTank numberOfGallons: numberOfGallons.
	aTank calculateTankProperties.
	^aTank.

Ok so now your code that figures out the number of sides and amount of glass
to use can reference shape and figure things out.

Of course I would not use hardcoded shapes in my code instead on the class
side I would create a protocol called Constants
	
Then I'd create a method called in Constants

FishTank class>>octagonalShape
	"return a symbol that represents an eight sided fishtank"
	^#octagon

Then I'd call 

aTank shape: self octagonalShape.

Instead.

You could also extend your class hierarchy to support different tanks.

FishTank subclass: RectangleFishTank

and

FishTank subclass: OctagonalFishTank

Now you can use your instance creation method to find out what instance to
create.  This makes things much easier because now your code for calculating
number of sides and amount of glass can just be written in each class and
all your   self shape = self class octagonalShape ifTrue ... code goes away.

RectangleFishTank class>>shape
	"return the shape of this subclass fishtank"
	^self rectangleShape

OctagonalFishTank class>>shape
	"return the shape of this subclass fishtank"
	^self octagonalShape

FishTank class>>newForShape: aShape numberOfGallons: aNumberOfGallons
	"return a new instance of a subclass matching aShape that holds
aNumberOfGallons"
	aClass := self allSubclasses detect: [:aClass | aClass shape =
aShape] ifNone: [NotAFishTankShapeThatWeSupportException signal].
	^aClass newForGallons: aNumberOfGallons.

And you can simplify your initialize with

FishTank>>initialize
	"set up default values for aFishTank"
	self glassSides: OrderedCollection new.
	self numberOfLights: 0 copy.
	self tankShape: self class shape.

Ok so back to someone else point.  What are you trying to do?

Hope this helps some.  Try not to override #basicNew, and only override new
if there is something about creating instances you want to change.  If you
are trying to affect how things are created there are lots of ways to make
this happen without changing new.

Happy Squeaking!

Ron Teitelbaum
President / Principal Software Engineer
US Medical Record Specialists

> -----Original Message-----
> From: Blake
> 
> Hey, all:
> 
> 	I figure this is a beginner question.
> 
> 	I get a big warning when I override certain methods. (Class
> methods?)
> 
> 	For example, if I want to set up the "contractless" part of my
> object, I
> do so by overriding #basicNew, and then setting the values that allow the
> instance of the object to function. This seems perfectly normal and
> reasonable, but I get this big warning about how terrible it might be.
> 
> 	I not even 100% clear on how it could be so terrible beyond that
> particular class. (I guess it's possible in this way to create an object
> that destabilizes the system?)
> 
> 	Am I doing this wrong/non-optimally? (Maybe I should be overriding
> #new
> instead of #basicNew, but I get the same dire warning for #new).
> 
> 	===Blake===
> 
> P.S. Seeing if this goes through; last message I sent warned me that I
> wasn't on the mailing list.
> _______________________________________________
> Beginners mailing list
> Beginners at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/mailman/listinfo/beginners



More information about the Beginners mailing list