Search code examples
initializationsmalltalkpharometaclass

Smalltalk: right way for custom construction


What book best describes right way to make custom constructors ?

For example, I want special file system (emulatied in RDBMS storage).

Object subclass: #C1_Object
C1_Object subclass: #C1_File
    instanceVariableNames: 'stream name'

Use case:

  1. C1_File new: 'blablabla'

or

  1. C1_File create: 'blablabla'

(1) looks native, but I have seen recommends don't override system allocation mechanics.

Next step: what is better

C1_File class>>create: aFileName
    ^ self new initialize: aFileName
C1_File>>initialize: aFileName
    name := aFileName.
    stream := C1_FileStream forceNewFileNamed: aFileName.

or

C1_File class>>create: aFileName
    | instance |
    instance := super new.
    instance name: aFileName.
    instance stream: ( C1_FileStream forceNewFileNamed: aFileName ).
    ^ instance initialize
C1_File>>initialize
    ^ super initialize

Solution

  • What book best describes right way to make custom constructors ?

    Kent Beck's Smalltalk Best Practice Patterns (which I highly recommend to keep at hand for reference) contains around 100 Smalltalk patterns, among which is also

    • Constructor Method
    • Constructor Parameter Method
    • Shortcut Constructor Method

    All of them discuss various aspects of object creation and parameter passing, however the common theme is increased understanding and clarity (and intention revealing selectors, which is another pattern).

    When you have

    C1_File create: 'blablabla'
    

    it is not clear what is actually going to happen; is C1_File going to create blablabla? What would that mean? As Esteban pointed out, it is better to name the argument... C1_File named: 'blablabla'; now I know what is going to happen.

    (1) looks native, but I have seen recommends don't override system allocation mechanics.

    You would have to mess with #basicNew to mess with allocation mechanics. If you look at implementation of #new, it actually doesn't do much.

    Behavior>>new
        ^ self basicNew initialize
    

    There also plenty of examples in the system:

    • OrderedCollection with: anItem
    • Color fromString: '#AC13D9' or Color r: 0.2 g: 0.5 b: 0.1
    • Point x: 10 y: 17
    • Readers/Writers often use on:.. STONReader on: aReadStream

    Note that the book mentioned in the beginning doesn't just show how to create a basic constructor, but also discusses other problems and challenges of the instance creation itself (e.g. when you have multiple different constructors to not blow up you method protocol, etc.)

    Class-side vs instance-side - more of an addendum for Esteban's answer:

    Keep the amount of regular behavior on the class-side to minimum; the class-side is primarily for meta-behavior --- managing the class itself, not doing the actual work.