Re: Issue 11 and Issue 12. Using #deepCopy, I have trouble understanding

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Issue 11 and Issue 12. Using #deepCopy, I have trouble understanding

Intrader 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.

<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
Reply | Threaded
Open this post in threaded view
|

Re: Issue 11 and Issue 12. Using #deepCopy, I have trouble understanding

Holger Guhl
  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
Reply | Threaded
Open this post in threaded view
|

Re: Issue 11 and Issue 12. Using #deepCopy, I have trouble understanding

Ladislav Lenart
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
Reply | Threaded
Open this post in threaded view
|

Re: Issue 11 and Issue 12. Using #deepCopy, I have trouble understanding

Reinout Heeck-2
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