Why Idioms?

Low-level patterns specific to a programming language

  • how to implement certain logic and relationships using a given language
  • may include guidelines for code formatting

Challenges

Good names: Choose names that clarify the objectโ€™s purpose

  • Name could encode type or semantic role (or both, depends on context)
  • Adhering to conventions can make reading easier

Good comments: Make comments succinct, concise, and grammatically correct

  • Too many comments can clutter the code
  • To few comments can leave the reader confused
  • Donโ€™t comment bad code - rewrite it!

Magic numbers: violates continuity (local changes)

Global state: might be used / modified incorrectly in some contexts

Consequences of meta-programming: can lead to

  • unexpected behavior
  • hardly traceable errors
  • hardly comprehensible code

Style Guides

  • ease reading and writing of (object-oriented) code
  • clear, easy to read, easy to understand more likely correct and reliable, easier to adapt, maintain and evolve
  • consistent coding style pretty-printing can be supported by automated tools (support and check the programmer)
  • Best guidelines are those that people want to follow (because they appreciate the benefit)

Law of Demeter

  • Donโ€™t talk to strangers; only talk to your immediate friends
  • Each unit should have only limited knowledge about other units: only units โ€œcloselyโ€ related to the current unit
  • simplifies complexity of programming and modifications
  • Class form: classes can only sent messages to argument classes (including the class itself) or instance variable classes
  • Object form: within a method, messages can only be sent to parameter objects (including itself), immediate part objects or created objects

Supplementary constraints

  1. minimizing code duplication
  2. minimizing number of arguments passed to methods
  3. minimizing number of methods per class

Idioms

Double Dispatch

  1. Send a message to the argument
  2. Append the class name of the receiver to the selector
  3. Pass the receiver as an argument

Super

Extending super: send a message to super in overriding method

BorderedFigure>>display
	super display.
	self displayBorder.

Modifying super: send a message to super in overriding method and then modify results

SuperFigure>>initialize
	color := Color white.
	size := 0 @ 0.
 
SubFigure>>initialize
	super initialize.
	color := Color beige.

Pluggable Behavior / Selector / Block

Parameterize behavior of an object: add a variable that will be used to trigger different behavior

  • Pluggable Selector: add a variable that contains a selector to be performed (ends with โ€˜Messageโ€™)
    • used for simple instance-specific behavior
  • Pluggable Block: add a variable to store a block (ends with โ€˜Blockโ€™)
    • used for complex Pluggable Behavior, that is not quite worth its own class
ListPane>>initialize
	printMessage := #printString.
 
ListPane>>printElement: anObject
	^ anObject perform: printMessage
 
"----------------------------------------------"
 
Car>>speedAdaptor
	^ PluggableAdaptor
	getBlock: [self speed]
	setBlock: [:newSpeed | self speed: newSpeed]
 
PluggableAdaptor>>value
^ getBlock value

Includes some meta-prgramming

Other Rules (excerpt)


Collections

Classes

  • Collection: represents one-to-many relationship
    • Ordered Collection: dynamically sized
    • Array: fixed size
      • ByteArray: can only hold numbers in range or
      • RunArray: compresses long runs of the same element
        • e.g. #(plain plain plain plain plain bold bold bold bold plain plain plain plain plain) 5-#plain 4-#bold 5-#plain
    • Set: unique elements
    • Bag: duplicates allowed
    • Dictionary: indexed by keys (map one kind of object to another)
      • stores associations like {{#plate} asBag. true. true} -> './items/plate.png'
      • can be used with add: or alternatively at:ifAbsentPut:
    • SortedCollection: keeps elements sorted (optionally a sort block can be passed)
      • e.g. self children asSortedCollection: [:a :b | a age < b age].
    • Interval: collection of numbers in sequence (Number>>to: or to:by:)

Equality method: Object>>= anObject

  • checks for equality
  • must be protected to fully test only compatible classes
  • needed for Set
Book>>= aBook
	(aBook isMemberOf: self class) ifFalse: [^ false].
	^ self author = aBook author & (self title = aBook title)`

Hashing method: Object>>hash

  • hashes the object
  • if you override =, override hash as well so that two objects that are equal return the same hash value
  • needed for hashed collections (like Dictionary)

isEmpty

  • isEmpty / ifEmpty: aBlock
  • notEmpty / ifNotEmpty: aBlock

includes | contains

  • includes: anObject checks if element is included
  • contains: aBlock equivalent to anySatisfy: aBlock

allSatisfy | anySatisfy

  • allSatisfy: aBlock checks if all elements satisfy the block condition
  • anySatisfy: aBlock checks if any element satisfies the block condition

select | reject | detect

  • select: aBlock returns a new collection containing all elements satisfying the condition
  • reject: aBlock returns a new collection containing all elements not satisfying the condition
  • detect: aBlock return the first element to satisfy the condition
    • not finding an element can be caught with ... ifNone: aBlock
  • can be optimized by using a Dictionary instead

inject | fold

  • inject: anObject into: aBlock can be used to to keep a running value while iterating
  • fold: binaryBlock can be used for simple fold operations (without initial value)
self children
	inject: 0
	into: [:sum :each | sum max: each age].
 
(1 to: 10) fold: [:a :b | a + b].

collect

  • collect: aBlock return a new collection where the specified computation has been executed on each element
(1 to: 10) collect: [:a | 2 * a].

do | doWithIndex | withIndexDo

  • used to enumerate (execute code for each element) a collection
  • e.g. aCollection do: [:each | ... ].