Avoid Null Checks

Damien Cassou, St├ęphane Ducasse and Luc Fabresse http://stephane.ducasse.free.fr

Anti If Campaign

Main >> showHappiness: animal
   animal isDog
      ifTrue: [ animal shakeTail ].
   animal isDuck
      ifTrue: [ animal quack ].
   animal isCat: [ ... ].

Branching (with if) based on the type of an object is bad:

Send messages instead

.

Anti If Campaign

Dog >> showHappiness
   self shakeTail
Duck >> showHappiness
   self quack
Cat >> showHappiness
   ...

Branching (with if) based on the type of an object is bad

Send messages instead

.

Do Not Return Nil

Inferencer >> rulesForFact: aFact
   self noRule ifTrue: [ ^ nil ]
   ^ self rulesAppliedTo: aFact

ifTrue: [ ^ nil ] forces every client to check for nil:

(inferencer rulesForFact: 'a')
   ifNotNil: [ :rules |
      rules do: [ :each | ... ]

Return Polymorphic Objects

When possible, replace if by polymorphic objects:

Inferencer >> rulesForFact: aFact
   self noRule ifTrue: [ ^ #() ]
   ^ self rulesAppliedTo: aFact

Your clients can just iterate and manipulate the returned value

(inferencer rulesForFact: 'a')
   do: [:each | ... ]

For Exceptional Cases, Use Exceptions

For exceptional cases, replace nil by exceptions:

FileStream >> nextPutAll: aByteArray
   canWrite ifFalse: [ self cantWriteError ].
   ...
FileStream >> cantWriteError
   (CantWriteError file: file) signal

Initialize Your Object State

Avoid nil checks by initializing your variables

Archive >> initialize
   super initialize.
   members := OrderedCollection new

Use Lazy Initialization if Necessary

You can defer initialization of a variable to its first use:

FreeTypeFont >> descent
   ^ cachedDescent ifNil: [
        cachedDescent := (self face descender * self pixelSize //
                               self face unitsPerEm) negated ]

Sometimes you have to check...

Sometimes you have to check before doing an action

ToolPalette >> nextAction
   self selectedTool
      ifNotNil: [ :tool | tool attachHandles ]

ToolPalette >> previousAction
   self selectedTool
      ifNotNil: [ :tool | tool detachHandles ]

Use NullObject

NoTool >> attachHandles
   ^ self
NoTool >> detachHandles
   ^ self
ToolPalette >> initialize
   self selectedTool: NoTool new
ToolPalette >> nextAction
   self selectedTool attachHandles
ToolPalette >> previousAction
   self selectedTool detachHandles

Conclusion

.

/