[Pharo-project] Beginner question about "self" in block
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 "mouseAction", which is BlockClosure, that looks like "[self toggleNeighboursOfCellAt: i at: j]". If "LOCell" is the "owner" of this block and also it is the one that evaluates it, shouldn't "self" refer to LOCell object? How BlockClosure desides where "self" actually points? Thanks for explanation. Jan
I think the self is bound at the block creation To be confirm, Ben On Jan 25, 2012, at 9:54 PM, Garret Raziel wrote:
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 "mouseAction", which is BlockClosure, that looks like "[self toggleNeighboursOfCellAt: i at: j]". If "LOCell" is the "owner" of this block and also it is the one that evaluates it, shouldn't "self" refer to LOCell object? How BlockClosure desides where "self" actually points?
Thanks for explanation. Jan
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 "mouseAction", which is BlockClosure, that looks like "[self toggleNeighboursOfCellAt: i at: j]". If "LOCell" is the "owner" of this block and also it is the one that evaluates it, shouldn't "self" refer to LOCell object? How BlockClosure desides where "self" actually points?
Thanks for explanation.
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
Ok, thanks for explanation to all of you. I'll read drafts from PBEII after I finish PBE :-).
I have another question, too short to create another thread. What happens if some object has method a: and b: AND a:b:? For example, SmallInt has method raisedTo:modulo:, but what will happen, if I define methods SmallInt>>raisedTo: and SmallIt>>modulo: and then execute "5 raisedTo: 6 modulo: 3"? Will it use "raisedTo:modulo:" method or will it use "raisedTo:" method and then send "modulo:" method to the result? Jan
On 25 January 2012 21:48, Garret Raziel <boloomka@gmail.com> wrote:
I have another question, too short to create another thread. What happens if some object has method a: and b: AND a:b:? For example, SmallInt has method raisedTo:modulo:, but what will happen, if I define methods SmallInt>>raisedTo: and SmallIt>>modulo: and then execute "5 raisedTo: 6 modulo: 3"? Will it use "raisedTo:modulo:" method or will it use "raisedTo:" method and then send "modulo:" method to the result?
Jan
The message names are greedy, so in your example "5 raisedTo: 6 modulo: 3" will send the #raisedTo:modulo: message to 5 with arguments 6 and 3. If you wanted to send #raisedTo: and then #modulo: you'd have to use parentheses: "(5 raisedTo: 6) modulo: 3". frank
Garret Raziel wrote:
Ok, so it automaticaly uses longest possible message?
Not the longest (in: the longest available), but whole. Concatenation of all xxx: keyword in the whole statement or parenthesised expression is used. I doesn't matter if #foo: exists if statement is 1 foo: 3 bar: 5; it is always #foo:bar:. Herby
So, keyword messages are slightly different from binary messages, because 5+4*3 doesn't invoke "+*" message so I don't have to write "(5+4)*3". If I had SmallInteger>>#multiplyBy and SmallInteger>>#add, I should use parenthesis "(5 add: 3) multiplyBy: 3".
Yes, Binary messages always involves two objects, so in your example there's two message sends. Be aware also that there's no arithmetic specific precedence rules ( 4 * 5 + 2 will return 22). The precedence is consistent among the whole language (unary->binary->keyworded). On Wed, Jan 25, 2012 at 7:55 PM, Garret Raziel <boloomka@gmail.com> wrote:
So, keyword messages are slightly different from binary messages, because 5+4*3 doesn't invoke "+*" message so I don't have to write "(5+4)*3". If I had SmallInteger>>#multiplyBy and SmallInteger>>#add, I should use parenthesis "(5 add: 3) multiplyBy: 3".
Just a passing thought.... It is common convention for example methods to be presented in text using '>>' preceded by the class. This is obviously needed to define the class/method relationship outside the image, but the whole example cannot be pasted directly into System Browser as the '>>' is not part of the Smalltalk syntax for defining methods. For those new to Pharo going through tutorials, copy/pasting the whole of the presented code eg [1] returns only the error "Nothing more expected" which is a bit cryptic to noobs who expect to follow the example verbatim. Once past understanding this, it continues (for me) to be a minor annoyance to have to select only the text following the '>>'. I wonder whether it would be beneficial for the compiler to handle '>>' at the start of a method definition. The System Browser would then jump to the created method. As well as beneficial to those experiencing Pharo for the first time, this might be useful as a general shortcut such that when browsing one class you can define a method for another class without first having to browse to that class. cheers, Ben [1] BExp>>testBlock: aBlock | t | t := nil. aBlock value
#>> already does something. Try printing "String >> #asDate". It fetches a compiled method. On 26 January 2012 08:15, Ben Coman <btc@openinworld.com> wrote:
Just a passing thought.... It is common convention for example methods to be presented in text using '>>' preceded by the class. This is obviously needed to define the class/method relationship outside the image, but the whole example cannot be pasted directly into System Browser as the '>>' is not part of the Smalltalk syntax for defining methods. For those new to Pharo going through tutorials, copy/pasting the whole of the presented code eg [1] returns only the error "Nothing more expected" which is a bit cryptic to noobs who expect to follow the example verbatim. Once past understanding this, it continues (for me) to be a minor annoyance to have to select only the text following the '>>'.
I wonder whether it would be beneficial for the compiler to handle '>>' at the start of a method definition. The System Browser would then jump to the created method. As well as beneficial to those experiencing Pharo for the first time, this might be useful as a general shortcut such that when browsing one class you can define a method for another class without first having to browse to that class.
cheers, Ben
[1] BExp>>testBlock: aBlock | t | t := nil. aBlock value
-- Milan Mimica http://sparklet.sf.net
Thanks Milan. Something new I've learnt. However I don't think this is a conflict. While your example works from Workspace, go where you define a method and try to get the following accepted. String >> #asDate ^1 The above is not valid, so no conflict in this context. Milan Mimica wrote:
#>> already does something. Try printing "String >> #asDate". It fetches a compiled method.
On 26 January 2012 08:15, Ben Coman <btc@openinworld.com> wrote:
Just a passing thought.... It is common convention for example methods to be presented in text using '>>' preceded by the class. This is obviously needed to define the class/method relationship outside the image, but the whole example cannot be pasted directly into System Browser as the '>>' is not part of the Smalltalk syntax for defining methods. For those new to Pharo going through tutorials, copy/pasting the whole of the presented code eg [1] returns only the error "Nothing more expected" which is a bit cryptic to noobs who expect to follow the example verbatim. Once past understanding this, it continues (for me) to be a minor annoyance to have to select only the text following the '>>'.
I wonder whether it would be beneficial for the compiler to handle '>>' at the start of a method definition. The System Browser would then jump to the created method. As well as beneficial to those experiencing Pharo for the first time, this might be useful as a general shortcut such that when browsing one class you can define a method for another class without first having to browse to that class.
cheers, Ben
[1] BExp>>testBlock: aBlock | t | t := nil. aBlock value
On Thu, Jan 26, 2012 at 9:57 AM, Ben Coman <btc@openinworld.com> wrote:
Thanks Milan. Something new I've learnt. Â However I don't think this is a conflict.
I agree, I don't see any conflict. I also like the proposal. Ben, do you think you could try to implement a prototype? I advise you to implement it either for OmniBrowser or for Nautilus and see if it makes sense. Thanks for the proposal -- Damien Cassou http://damiencassou.seasidehosting.st "Lambdas are relegated to relative obscurity until Java makes them popular by not having them." James Iry
Damien Cassou wrote:
On Thu, Jan 26, 2012 at 9:57 AM, Ben Coman <btc@openinworld.com> wrote:
Thanks Milan. Something new I've learnt. However I don't think this is a conflict.
I agree, I don't see any conflict. I also like the proposal. Ben, do you think you could try to implement a prototype? I advise you to implement it either for OmniBrowser or for Nautilus and see if it makes sense.
Thanks for the proposal
I can't do anything for the next six months - I'm a long way behind where I wanted to be with my dissertation. I'll be happy to give it a go after that is complete. For now, I just let out the idea while it occurs to me, so it does get lost.
I think Damien meant the other Ben(jamin) :) Cheers, Doru On Thu, Jan 26, 2012 at 10:35 AM, Ben Coman <btc@openinworld.com> wrote:
Damien Cassou wrote:
On Thu, Jan 26, 2012 at 9:57 AM, Ben Coman <btc@openinworld.com> wrote:
Thanks Milan. Something new I've learnt. Â However I don't think this is a conflict.
I agree, I don't see any conflict. I also like the proposal. Ben, do you think you could try to implement a prototype? I advise you to implement it either for OmniBrowser or for Nautilus and see if it makes sense.
Thanks for the proposal
I can't do anything for the next six months - I'm a long way behind where I wanted to be with my dissertation. I'll be happy to give it a go after that is complete. Â For now, I just let out the idea while it occurs to me, so it does get lost.
-- www.tudorgirba.com "Every thing has its own flow"
I was wondering if he was talking about me or not :) (the other) Ben ;) On Jan 26, 2012, at 10:47 AM, Tudor Girba wrote:
I think Damien meant the other Ben(jamin) :)
Cheers, Doru
On Thu, Jan 26, 2012 at 10:35 AM, Ben Coman <btc@openinworld.com> wrote:
Damien Cassou wrote:
On Thu, Jan 26, 2012 at 9:57 AM, Ben Coman <btc@openinworld.com> wrote:
Thanks Milan. Something new I've learnt. However I don't think this is a conflict.
I agree, I don't see any conflict. I also like the proposal. Ben, do you think you could try to implement a prototype? I advise you to implement it either for OmniBrowser or for Nautilus and see if it makes sense.
Thanks for the proposal
I can't do anything for the next six months - I'm a long way behind where I wanted to be with my dissertation. I'll be happy to give it a go after that is complete. For now, I just let out the idea while it occurs to me, so it does get lost.
-- www.tudorgirba.com
"Every thing has its own flow"
On Jan 26, 2012, at 8:15 AM, Ben Coman wrote:
Just a passing thought.... It is common convention for example methods to be presented in text using '>>' preceded by the class. This is obviously needed to define the class/method relationship outside the image, but the whole example cannot be pasted directly into System Browser as the '>>' is not part of the Smalltalk syntax for defining methods. For those new to Pharo going through tutorials, copy/pasting the whole of the presented code eg [1] returns only the error "Nothing more expected" which is a bit cryptic to noobs who expect to follow the example verbatim. Once past understanding this, it continues (for me) to be a minor annoyance to have to select only the text following the '>>'.
would be nice!
I wonder whether it would be beneficial for the compiler to handle '>>' at the start of a method definition. The System Browser would then jump to the created method. As well as beneficial to those experiencing Pharo for the first time, this might be useful as a general shortcut such that when browsing one class you can define a method for another class without first having to browse to that class.
Ideally I would like to have also the support for coral syntax :)
cheers, Ben
[1] BExp>>testBlock: aBlock | t | t := nil. aBlock value
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. Now having done that, I think I missed an alternative implementation... Library >> addBook: aBook aBook addToLibrary: self withInternalCollection: books Book>>addToLibrary: aLibrary withInternalCollection: libraryInternalBooksCollection libraryInternalBooksCollection add: self. library := aLibrary. Book>>addToLibrary: aLibrary aLibrary addBook: self. and I'm not really sure of the pros & cons of each approach. Thoughts anyone?
Hi, I like the "withBackLink:" one more because the other solution exposes how books are implemented on Library by passing the collection through. Better to let library manage books than to add it directly.
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.
However, I'm not sure that you are adding *that* much value by using the "withBackLink:" because this reads a bit easier: Book>>addToLibrary: aLibrary aLibrary protectedAddBook: self. library := aLibrary Library>>protectedAddBook: aBook books add: aBook We build in a bit of an integrity framework that helps: Book>>checkIntegrity self assert: (library hasBook: self) Library>>checkIntegrity books do: [ :book | self assert: book library == self ] After each test, in the tearDown, we call this on all objects created in the test. Also, we run this daily on production databases and fix failures (not often enough though!). Cheers Otto
Yes!
Hi,
I like the "withBackLink:" one more because the other solution exposes how books are implemented on Library by passing the collection through. Better to let library manage books than to add it directly.
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.
However, I'm not sure that you are adding *that* much value by using the "withBackLink:" because this reads a bit easier:
Book>>addToLibrary: aLibrary aLibrary protectedAddBook: self. library := aLibrary
Library>>protectedAddBook: aBook books add: aBook
We build in a bit of an integrity framework that helps:
Book>>checkIntegrity self assert: (library hasBook: self)
Library>>checkIntegrity books do: [ :book | self assert: book library == self ]
After each test, in the tearDown, we call this on all objects created in the test. Also, we run this daily on production databases and fix failures (not often enough though!).
Cheers Otto
I guess that in naked objects book they discussed some patterns for relationships. What I would love to have is first class slots so that we can easily express relationships like the ones you describe. But I have too busy. I'm rereading the paper of toon, camillo et all to see what we could reasonably do. Stef On Jan 27, 2012, at 6:11 AM, 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.
Now having done that, I think I missed an alternative implementation...
Library >> addBook: aBook aBook addToLibrary: self withInternalCollection: books
Book>>addToLibrary: aLibrary withInternalCollection: libraryInternalBooksCollection libraryInternalBooksCollection add: self. library := aLibrary.
Book>>addToLibrary: aLibrary aLibrary addBook: self.
and I'm not really sure of the pros & cons of each approach. Thoughts anyone?
Stéphane Ducasse wrote:
I guess that in naked objects book they discussed some patterns for relationships. What I would love to have is first class slots so that we can easily express relationships like the ones you describe. But I have too busy. I'm rereading the paper of toon, camillo et all to see what we could reasonably do.
I found the description of Bidrectional Associations interesting [1], as well as the naming convention for Derived Fields and Actions. [1] http://www.nakedobjects.org/book/section19.html
Stef
On Jan 27, 2012, at 6:11 AM, 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.
Now having done that, I think I missed an alternative implementation...
Library >> addBook: aBook aBook addToLibrary: self withInternalCollection: books
Book>>addToLibrary: aLibrary withInternalCollection: libraryInternalBooksCollection libraryInternalBooksCollection add: self. library := aLibrary.
Book>>addToLibrary: aLibrary aLibrary addBook: self.
and I'm not really sure of the pros & cons of each approach. Thoughts anyone?
we want that in pharo. Since years... Stef On Jan 27, 2012, at 7:26 PM, Ben Coman wrote:
Stéphane Ducasse wrote:
I guess that in naked objects book they discussed some patterns for relationships. What I would love to have is first class slots so that we can easily express relationships like the ones you describe. But I have too busy. I'm rereading the paper of toon, camillo et all to see what we could reasonably do.
I found the description of Bidrectional Associations interesting [1], as well as the naming convention for Derived Fields and Actions.
[1] http://www.nakedobjects.org/book/section19.html
Stef
On Jan 27, 2012, at 6:11 AM, 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.
Now having done that, I think I missed an alternative implementation...
Library >> addBook: aBook aBook addToLibrary: self withInternalCollection: books
Book>>addToLibrary: aLibrary withInternalCollection: libraryInternalBooksCollection libraryInternalBooksCollection add: self. library := aLibrary.
Book>>addToLibrary: aLibrary aLibrary addBook: self.
and I'm not really sure of the pros & cons of each approach. Thoughts anyone?
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
participants (12)
-
Ben Coman -
Benjamin -
Damien Cassou -
Frank Shearar -
Gabriel Cotelli -
Garret Raziel -
Henrik Johansen -
Herby VojÄÃk -
Milan Mimica -
Otto Behrens -
Stéphane Ducasse -
Tudor Girba