Most interesting discussion and learning from your posts.
I believe now that in a case where I should use #deepCopy, I should write a TestCase method to verify that my assumption(s) are correct and allow me to refactor later. <The problem as described to Anthny and Holger is:> The problem at hand is a small web application with a subcomponent that offers an editor to edit a contact (method '#editContact aContact:'). The editor offers buttons to Save and Cancel (Save returns #true and Cancel returns #false). A first crack to the puzzle posed by the last paragraph of chapter 12.2 of Dynamic Web Development with Seaside is to write <code> editContact: aContact | copy | copy := aContact copy. (editor contact: copy) onAnswer: [ :answer | answer ifFalse: [MyContact removeContact: aContact; addContact: copy. ] ] </code> The problem with this is that it removes contacts each time that 'Cancel' is clicked. Therefore next time, #removeContact does not find the contact in the collection. I am now thinking of handing the editor a deep copy of the contact to be edited, and have the #onAnswer as above. In the #ifTrue path I would take all the instance variables of a contact and store them in the instance variables of the parameter to #editContact (the example being followed in in chapter 12.2 of Dynamic Web Development with Seaside - the last paragraph refers to a solution in chapter 11.5 which only works because the subcomponent is modal and the main component is rerendered) </The problem as described to Anthny and Holger is:> Thanks again for the terrific lessons on how to use #deepCopy, copy, '#=', '#==', inheritance, and #hash. I seemed to have been taking OOP too much at heart - I should from now on think of MOP (Model Oriented Programming) and be very careful in limiting the breath of methods to make them applicable in more cases ;-) As an aside problem to understand, why should #deepCopy cause a failure when ('x = x deepCopy') is executed. Seems to me that the implementation of #deepCopy is incorrect, or my understanding of #deepCopy, inheritance, etc. is way off. Seems to me that #deepCopy should result in a clone, with the possiblity of succeeding when doing ('x == x deepCopy'). Thanks again to all, and I eagerly will look at your answers and suggestions. P.S. I am not sure that I should answer the messages privately as the private message does not show in the list. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Go ahead posting to the entire list.
You have seen that we are having a very open discussion here, and lots of members merrily joined in. And other readers may have learned from the thread as well, without answering. If you're in doubt, just think whether you would like other members cite and publish parts of the communication exchanged so far. As long as you keep the friendly tone and nobody is offended or embarrassed, then nobody will complain. Cheers Holger Am 05.05.2011 02:37, schrieb intrader: > Most interesting discussion and learning from your posts. > > I believe now that in a case where I should use #deepCopy, I should > write a TestCase method to verify that my assumption(s) are correct and > allow me to refactor later. ... > > P.S. I am not sure that I should answer the messages privately as the > private message does not show in the list. > _______________________________________________ _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Intrader Intrader
Hello.
On 5.5.2011 02:37, intrader wrote: > Most interesting discussion and learning from your posts. > > I believe now that in a case where I should use #deepCopy, I should > write a TestCase method to verify that my assumption(s) are correct and > allow me to refactor later. > > <The problem as described to Anthny and Holger is:> > > The problem at hand is a small web application with a subcomponent that > offers an editor to edit a contact (method '#editContact aContact:'). > The editor offers buttons to Save and Cancel (Save returns #true and > Cancel returns #false). > > A first crack to the puzzle posed by the last paragraph of chapter 12.2 > of Dynamic Web Development with Seaside is to write > > <code> > editContact: aContact > | copy | > copy := aContact copy. > (editor contact: copy) onAnswer: [ :answer | > answer ifFalse: [MyContact removeContact: aContact; addContact: > copy. > ] > ] > </code> > > The problem with this is that it removes contacts each time that > 'Cancel' is clicked. Therefore next time, #removeContact does not find > the contact in the collection. I've read the relevant sections from the Seaside book and they use the following (notice the #ifTrue: message): answer ifTrue: [MyContact removeContact: aContact; addContact: copy]. You want to swap the contacts only when the user clicked on a Save button. Otherwise there's nothing that needs to be done. However be aware that I am not a Seaside user. > I am now thinking of handing the editor a deep copy of the contact to be > edited, and have the #onAnswer as above. In the #ifTrue path I would > take all the instance variables of a contact and store them in the > instance variables of the parameter to #editContact (the example being > followed in in chapter 12.2 of Dynamic Web Development with Seaside - > the last paragraph refers to a solution in chapter 11.5 which only works > because the subcomponent is modal and the main component is rerendered) > > </The problem as described to Anthny and Holger is:> > > Thanks again for the terrific lessons on how to use #deepCopy, copy, > '#=', '#==', inheritance, and #hash. > > I seemed to have been taking OOP too much at heart - I should from now > on think of MOP (Model Oriented Programming) and be very careful in > limiting the breath of methods to make them applicable in more cases ;-) > > As an aside problem to understand, why should #deepCopy cause a failure > when ('x = x deepCopy') is executed. Seems to me that the implementation > of #deepCopy is incorrect, or my understanding of #deepCopy, > inheritance, etc. is way off. Seems to me that #deepCopy should result > in a clone, with the possiblity of succeeding when doing ('x == x > deepCopy'). Well: * #== is a primitive that returns true only if the receiver and the argument represent the exact same object (both point to the same memory location). You should never override it in your subclasses. * #= returns true if the receiver and the argument are 'equal'. What exactly that means is defined by the receiver's implementation of #=. See for example Magnitude subclasses for various implementations of #=. By default #= is implemented as #==. The reason for this was already explained very well by other posters. * #shallowCopy is a primitive that creates a copy of the receiver. So original == copy always returns false. BUT all copy's instance variables are the the same (in the sense of #==) as the ones in the original. You should never override it in your subclasses. * #copy looks like this: Object>>copy ^self shallowCopy postCopy In other words: New instance of the receiver is created which shares all instance variables with the receiver. #postCopy is invoked on the NEW instance which can modify its state further. It can for example copy some of its instance variables so that they are not identical with those in the original anymore, it can reset some cached instance variables to nil and so on. If you want to change meaning of #copy, you should override #postCopy in your subclasses. * #deepCopy name _suggests_ that it will invoke #copy on the receiver and also on all its instance variables (and recursively on their instance variables and so on). However this is only my guess, because I don't have such a method in my image. However if it works this way, there is potential for endless looping. Imagine all copied objects as nodes in a graph with instance variables as directed links between them from the holder to the value. If this graph contains cycles (back references), #deepCopy will never terminate eventually crashing the image with out of memory error. * You can of course implement your own methods in the spirit of #copy (if there's more than one way to copy your objects for different purposes): MyClass>>specialCopy ^self shallowCopy postSpecialCopy By now you should understand that the following are ALWAYS false: x == x shallowCopy x == x copy x == x deepCopy x == x specialCopy and that the following may return BOTH true of false depending on the implementation of #=: x = x shallowCopy x = x copy x = x deepCopy x = x specialCopy > Thanks again to all, and I eagerly will look at your answers and > suggestions. > > P.S. I am not sure that I should answer the messages privately as the > private message does not show in the list. Please always answer to the list. I think that is (or at least should be) the preferred way so the conversation can help others in their future endeavours. HTH, Ladislav Lenart _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Intrader Intrader
On 5/5/2011 2:37 AM, intrader wrote:
> I am now thinking of handing the editor a deep copy of the contact to be > edited, and have the #onAnswer as above. In the #ifTrue path I would > take all the instance variables of a contact and store them in the > instance variables of the parameter to #editContact That is a good idea, we use a similar pattern in all our UI development (whether it is Seaside or VW clients), however we don't hand over a deep copy. Particularly in VW clients there are system ivars that manage dependencies between the domain class (Contract) and the UI elements. These ivars don't want to be altered during the lifetime of the UI, so instead of handing over copies in editor UIs we would instantiate a Contract *only once* in the UI. This Contract can be told to #clear itself or to #updateFrom: an other Contract (in order to start editing an existing Contract). Once editing is done the Contract in the 'database' can be told to #updateFrom: the Contract in the editor. (the same #updateFrom: but used in the 'other' direction). We found that strictly adhering to this pattern removed a lot of potential bugs. It introduces new potential bugs too, this class of bugs is that #clear and #updateFrom: are not correctly maintained after changes to the domain classes. However since they are 'always the same' bugs we see it takes almost no time to locate and fix them :-) > P.S. I am not sure that I should answer the messages privately as the > private message does not show in the list. Answer to the list please. Enjoy! R - _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |