The Dependency Mechanism - part 1

From Cuis CookBook
Revision as of 20:41, 12 May 2025 by Nmingott (talk | contribs) (imported material)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
  • Smalltalk has a way to keep a relation between objects in the sense that, if objA changes then objB gets immediately informed about it.
  • The classic way for an object to keep updated about another object state is polling, that is objB checks every X milliseconds the state of objA. But this is very much resource consuming and, if possible, it should be avoided. Smalltalk has more sophisticated ways to solve this problem.
  • The first thing you need to know is that there is a classic mechanism to do it but in Cuis it has been obsoleted. We will look at it in any case, because you can find it in books.

The Classic Mechanism of Parent and Dependent

  • I red about this mechanism in the two books; the content there has to be adapted to run in Cuis but there is still some good interesting contents.
    • "Smalltalk by Example" by Alec Sharp, see Chapter 19. pg.149.
    • "Smalltalk an introduction to application development with VisualWorks" by Hopkins & Horan, see Chapter 27, pg.287.
  • We will explain this mechanism with the simplest example possible
  • There are two objects, objA and objB which actually contains only just a number in the instance variable value.
  • We want that when objA changes its value to, say, 10, then objB value must become automatically 20, that is, it must double objA value.
  • So let's define 2 classes and a few methods, very simple stuff:
Object subclass: MyParentNumber
    instanceVariableNames: 'value'

MyParentNumber >> initialize
    value := 0 
    ^ self 

Object subclass: MyDependentNumber
    instanceVariableNames: 'value'

MyDependentNumber >> initialize
    value := 0 
    ^ self

MyDependentNumber >> update: aParameter
    |outStr|
    outStr := 'One of my parent changed and toldme "{1}" ! I may do something !' format: {aParam. }. 
    Transcript show: outStr .          
  • It is all classic except for the update: aParameter. That is the method that will be called automatically when objA will get updated.
  • So let's now create objA ,  objB and make objB dependent on objA
objA _ MyParentNumber new.
objB _ MyDependentNumber new.  

". this makes the connection, the dependency relation "
objA addDependent: objB. 
  • Now, open your Transcript and run this
objA changed: #foobar.
  • You will notice that in the transcript there is written "One of my parent changed and told me "foobar" ! I may do something !"
  • Aha ! It works. You sent a message changed:#aParameter to objA and the message update:aParameter was sent to objB.
  • Now we have all the pieces to complete our objective, we just need to glue them together.
  • Before that, let's break the connection between objA and objB and show that nothing happens anymore.
objA removeDependent: objB.
objA changed: #foobar. 
objA changed: #foobar. 
objA changed: #foobar. 
" ... nothing intereseting appears into the Transcript now"
  • So, here is the new version of the code, the code for the new classes MyParentNumber.st and MyDependentNumber.st is available for download and file-in.
Object subclass: MyParentNumber
    instanceVariableNames: 'value'

MyParentNumber >> initialize
    value := 0 
    ^ self 

MyParentNumber >> value
    ^ value 

MyParentNumber >> value: aNumber
     value := aNumber.
     "when i change, i inform my dependents that i did, they will check what changed.
      the value of the parameter #iChanged is insignificant. "
     self changed: #iChanged. 

Object subclass: MyDependentNumber
    instanceVariableNames: 'value parent'

MyDependentNumber Class >> newWithParent: anObject
    ^ super new initializeWithParent: anObject

MyDependentNumber >> initializeWithParent: anObject
    value := 0.
    parent := anObject . 
    parent addDependent: self.
    ^ self 

MyDependentNumber >> value
   ^ value 

MyDependentNumber >> update: aParameter
    |vPar vMe |
    ". i don't check the parameter, since I know that i am bound to only one Parent and i know 
       i can read its state when he tells me that he changed. "
    vPar := parent value.  
    vMe := vPar * 2.
    value := vMe.
    Transcript show: ('my parent value is:{1} and mine is value:{2}' format: {vPar. vMe} ).  
  • Let's try it out
objA _ MyParentNumber new.
objB _ MyDependentNumber newWithParent: objA. 

objA value.   "=> 0"
objB value .  "=> 0"

objA value: 10.  
objB value.        " => 20"
  • We see it works and we are very happy with that.
  • Now the sour part, this mechanism is deprecated in Cuis. The methods addDependent:, changed, update: ... are defined in Object. And if you look at their implementation you will see the mechanism with is used now, called Observer pattern, which we will see in another page.