On Jan 27, 2012, at 6:11 53AM, Ben Coman wrote:

> Stéphane Ducasse wrote:
>> Welcome
>> 
>> 
>>  
>>> Hi, I have one begginer question. It is may be simple, but it very baffles 
>>> me.
>>> 
>>> I am reading Pharo by Example (great book btw, thanks!). I'm in chapter two 
>>> where I'm creating Lights Out game. There is this simple code 
>>> http://pastebin.com/eQregZ35. What baffles me is line 10. I assign "Block 
>>> of code" to mouseAction variable of LOCell. In this Block, there is "self", 
>>> that obviously refers to LOGame object in that time. But when is this Block 
>>> actualy EVALUATED (when I click on Cell), "self" should be reffering to 
>>> LOCell object, isn't it? If I inspect one LOCell, inspector shows that it 
>>> has instance variable
>>>    
>> 
>> Here is a draft of a next chapter on block :)
>> But I should finish it :)
>> ------------------------------------------------------------------------
>> 
>> 
>> But I want to add how block are implemented at the bye code level so it take 
>> times because not that many people are helping, so I have to learn first.
>> 
>> Stef
>>  
> Thanks Stef.  A very enlightening read.  Its has helped in an example I'll 
> relate for other neophytes, and in case there are any traps or patterns I am 
> missing.
> 
> I have been struggling with how to implement a bidirectional relationship 
> between two classes such that consistency is enforced.   Take for instance 
> the following classes...
> Object subclass: #Book   instanceVariableNames: 'bookTitle library'
> Object subclass: #Library instanceVariableNames: 'libraryName books'
> 
> I want both the 'books' and 'library' instvars to remain private - meaning 
> that I don't want the default accessors providing direct access to either.  
> Then a method like 'Library>>addBook: aBook' which can update its internal 
> state modifying the 'books' collection cannot update the internal 'library' 
> state of 'aBook' - without Book having a setter method to directly change the 
> 'library' instvar - which I want to avoid having.  Trying to resolve this led 
> me into recursion hell with too much cross checking and guarding code.
> 
> What I was wanting was a way to expose the private state of one object to 
> another object in a controlled manner.  So now I think this might be achieved 
> like this...
> 
> Library>>addBook: aBook
>   aBook addToLibrary: self.
> 
> Book>>addToLibrary: aLibrary
>   aLibrary addBook: self withBackLink: [ :backlinkValue | library := 
> backlinkValue ].
> 
> Library>>addBook: aBook withBackLink: setBacklinkBlock
>   books ifNil: [ books := OrderedCollection new ].
>   books add: aBook.
>   setBacklinkBlock value: self.

When forgoing accessors to keep state private, it's usually a good idea to 
avoid lazy initialization, since you cannot centralize the check anywhere:

Library >> Initialize
books := OrderedCollection new.

Another common solution, is use two "levels" of methods: (basic* usually put in 
a private category)

Book >> addToLibrary: aLibrary
        self basicAddToLibrary: aLibrary.
        aLibrary basicAddBook: self.

Library >> addBook: aBook
        self basicAddBook: aBook.
        aBook uncheckedAddToLibrary: self.

Book basicAddToLibrary: aLibrary
        library := aLibrary.

Library >> basicAddBook: aBook
        books add: aBook

Basically, split the methods ensuring consistency from those actually modifying 
state.
Note that basicAddToLibrary is in essence a "default accessor" in this case, 
but not intended for public consumption.
IMHO, clarity in smalltalk is usually better achieved by categorization, 
naming, and comments than creating a restrictive API. 

Cheers,
Henry

Reply via email to