Object>>copyTwoLevel

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

Object>>copyTwoLevel

Panu Suominen
Hi,

we have a problem where we must create audit trail of changes made to
business objects. Also things should run inside transaction. Our first
approach was to create so called command objects from every change but
these would be hard to maintain by hand. For example there would be
ChangePersonName, ChangeXXXName classes and these would have to be
hand created in name: -mehtods. More "clever" approach we come up with
is to copy original object and use proxy that records messages send to
it and sends them to the copy. Also this proxy creates new proxy when
copy returns values. These proxies record message sends to transaction
and when transaction is ready these recorded message from all of the
proxies are done to the actual objects instead of copies.

To create usable copies I found method that (shallow) copies the
actual object and its instance variables (Object>>copyTwoLevel). The
method is marked to be deprecated soon.
Why is that and is there some alternative way of doing this kind of copy?
Also if you know some way to trivially handle the audit trail problem
I would like to hear... :)


--
Panu

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Igor Stasenko
On 4 May 2011 15:02, Panu Suominen <[hidden email]> wrote:

> Hi,
>
> we have a problem where we must create audit trail of changes made to
> business objects. Also things should run inside transaction. Our first
> approach was to create so called command objects from every change but
> these would be hard to maintain by hand. For example there would be
> ChangePersonName, ChangeXXXName classes and these would have to be
> hand created in name: -mehtods. More "clever" approach we come up with
> is to copy original object and use proxy that records messages send to
> it and sends them to the copy. Also this proxy creates new proxy when
> copy returns values. These proxies record message sends to transaction
> and when transaction is ready these recorded message from all of the
> proxies are done to the actual objects instead of copies.
>
> To create usable copies I found method that (shallow) copies the
> actual object and its instance variables (Object>>copyTwoLevel). The
> method is marked to be deprecated soon.
> Why is that and is there some alternative way of doing this kind of copy?
> Also if you know some way to trivially handle the audit trail problem
> I would like to hear... :)
>
>

I think that this is too special kind of copy to be provided by
default in kernel (so whoever stated that this will be deprecated,
i agree with him ;).
What you can do is to copy down this method to the root class of your
domain hierarchy..
I.e.
consider that all your domain objects having single root superclass ,
like MyDomainObject

and then you're free to use this specific kind of copy for your
classes, without relying on it in Object protocol.

> --
> Panu
>

--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Andres Fortier-2
In reply to this post by Panu Suominen
Hi Panu. I don't know if immutability is available in Pharo, but if it
is it may work for you. You basically mark an object as immutable and
register an exception handler. When an immutable object's i.v. is
assigned a new value, an exception is raised and the assignment is left
pending. There you can log the change and effectively apply the
assignment to the object.

HTH,
         Andrés

Panu Suominen escribió:

> Hi,
>
> we have a problem where we must create audit trail of changes made to
> business objects. Also things should run inside transaction. Our first
> approach was to create so called command objects from every change but
> these would be hard to maintain by hand. For example there would be
> ChangePersonName, ChangeXXXName classes and these would have to be
> hand created in name: -mehtods. More "clever" approach we come up with
> is to copy original object and use proxy that records messages send to
> it and sends them to the copy. Also this proxy creates new proxy when
> copy returns values. These proxies record message sends to transaction
> and when transaction is ready these recorded message from all of the
> proxies are done to the actual objects instead of copies.
>
> To create usable copies I found method that (shallow) copies the
> actual object and its instance variables (Object>>copyTwoLevel). The
> method is marked to be deprecated soon.
> Why is that and is there some alternative way of doing this kind of copy?
> Also if you know some way to trivially handle the audit trail problem
> I would like to hear... :)
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Stéphane Ducasse
In reply to this post by Igor Stasenko

On May 4, 2011, at 3:16 PM, Igor Stasenko wrote:

> On 4 May 2011 15:02, Panu Suominen <[hidden email]> wrote:
>> Hi,
>>
>> we have a problem where we must create audit trail of changes made to
>> business objects. Also things should run inside transaction. Our first
>> approach was to create so called command objects from every change but
>> these would be hard to maintain by hand. For example there would be
>> ChangePersonName, ChangeXXXName classes and these would have to be
>> hand created in name: -mehtods. More "clever" approach we come up with
>> is to copy original object and use proxy that records messages send to
>> it and sends them to the copy. Also this proxy creates new proxy when
>> copy returns values. These proxies record message sends to transaction
>> and when transaction is ready these recorded message from all of the
>> proxies are done to the actual objects instead of copies.


mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).

>> To create usable copies I found method that (shallow) copies the
>> actual object and its instance variables (Object>>copyTwoLevel). The
>> method is marked to be deprecated soon.
>> Why is that and is there some alternative way of doing this kind of copy?

why copy is not enough for you?
and you redefine postCopy to copy the instance variables?

>> Also if you know some way to trivially handle the audit trail problem
>> I would like to hear... :)
>>
>>
>
> I think that this is too special kind of copy to be provided by
> default in kernel (so whoever stated that this will be deprecated,
> i agree with him ;).

:) I know that guy.


> What you can do is to copy down this method to the root class of your
> domain hierarchy..
> I.e.
> consider that all your domain objects having single root superclass ,
> like MyDomainObject
>
> and then you're free to use this specific kind of copy for your
> classes, without relying on it in Object protocol.

+1

>
>> --
>> Panu
>>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>


Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

jfabry

On 04 May 2011, at 17:30, Stéphane Ducasse wrote:

>
> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).


Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers?

--
Johan Fabry  
[hidden email] - http://dcc.uchile.cl/~jfabry
PLEIAD Lab - Computer Science Department (DCC) - University of Chile




Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Igor Stasenko
On 5 May 2011 01:59, Johan Fabry <[hidden email]> wrote:
>
> On 04 May 2011, at 17:30, Stéphane Ducasse wrote:
>
>>
>> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).
>
>
> Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers?
>

Sorry i'm not familiar with methodwrappers.

The basic model is separation of proxy and handler. Proxy acts only as
a message trap,
while handler is actually responsible for handling messages trapped by proxy.

Mariano builds on top of that, because he wants to replace classes
and/or methods with proxies,
and this requires a special handling (class proxy should obey
VM-specific Behavior format,
and method proxy should implement #run:in:as: when installed in method
dictionary ).

So, i guess that proxies which representing compiled methods could act
similar to method wrappers.
But of course you still have to implement all intall/deinstall
management et al..

The only advantage of new proxies comparing to usual proxies based on
#DNU pattern that
they guarantee a clear separation between meta-levels, i.e. even if
you send #doesNotUnderstand:
message to a proxy, this message will be trapped and handled by
handler as any other.


--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Panu Suominen
In reply to this post by Andres Fortier-2
2011/5/4 andres <[hidden email]>:
> Hi Panu. I don't know if immutability is available in Pharo, but if it is it
> may work for you. You basically mark an object as immutable and register an
> exception handler. When an immutable object's i.v. is assigned a new value,
> an exception is raised and the assignment is left pending. There you can log
> the change and effectively apply the assignment to the object.

This sounds good but it seems that Squeak VM does not yet contain
immutable objects.
I am not sure.

--
Panu

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Marcus Denker-4
In reply to this post by Andres Fortier-2

On May 5, 2011, at 8:19 AM, Panu Suominen wrote:

> 2011/5/4 andres <[hidden email]>:
>> Hi Panu. I don't know if immutability is available in Pharo, but if it is it
>> may work for you. You basically mark an object as immutable and register an
>> exception handler. When an immutable object's i.v. is assigned a new value,
>> an exception is raised and the assignment is left pending. There you can log
>> the change and effectively apply the assignment to the object.
>
> This sounds good but it seems that Squeak VM does not yet contain
> immutable objects.
> I am not sure.


No. They were implemented in the Squeak VM that NewSpeak uses.
So the code is out there.

        Marcus



--
Marcus Denker  -- http://www.marcusdenker.de
INRIA Lille -- Nord Europe. Team RMoD.


Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

NorbertHartl

Am 05.05.2011 um 08:24 schrieb Marcus Denker:

>
> On May 5, 2011, at 8:19 AM, Panu Suominen wrote:
>
>> 2011/5/4 andres <[hidden email]>:
>>> Hi Panu. I don't know if immutability is available in Pharo, but if it is it
>>> may work for you. You basically mark an object as immutable and register an
>>> exception handler. When an immutable object's i.v. is assigned a new value,
>>> an exception is raised and the assignment is left pending. There you can log
>>> the change and effectively apply the assignment to the object.
>>
>> This sounds good but it seems that Squeak VM does not yet contain
>> immutable objects.
>> I am not sure.
>
>
> No. They were implemented in the Squeak VM that NewSpeak uses.
> So the code is out there.
>
Isn't there a WriteBarrier implementation somewhere. I don't know really but I think at least magma is using it.

Norbert



Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Panu Suominen
In reply to this post by Stéphane Ducasse
2011/5/5 Stéphane Ducasse <[hidden email]>:
> why copy is not enough for you?
> and you redefine postCopy to copy the instance variables?

Because it would involve manual labour for any object that is going to
be used in business logic. This would create artificial requirement
that is easily forgotten. However first try-out of this approach used
postCopy in domain objects.

I thought that copyTwoLevel is going to be deprecated because it is
too specific. However I am not sure whether this is actually true. It
depends how often copying objects is necessary.
The deprecation is not a problem. I can easily just create utility
class that copies objects like copyTwoLevel.

--
Panu

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Mariano Martinez Peck
In reply to this post by Igor Stasenko


On Thu, May 5, 2011 at 4:30 AM, Igor Stasenko <[hidden email]> wrote:
On 5 May 2011 01:59, Johan Fabry <[hidden email]> wrote:
>
> On 04 May 2011, at 17:30, Stéphane Ducasse wrote:
>
>>
>> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).
>
>
> Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers?
>

Sorry i'm not familiar with methodwrappers.

The basic model is separation of proxy and handler. Proxy acts only as
a message trap,
while handler is actually responsible for handling messages trapped by proxy.

Mariano builds on top of that, because he wants to replace classes
and/or methods with proxies,
and this requires a special handling (class proxy should obey
VM-specific Behavior format,
and method proxy should implement #run:in:as: when installed in method
dictionary ).

So, i guess that proxies which representing compiled methods could act
similar to method wrappers.
But of course you still have to implement all intall/deinstall
management et al..

The only advantage of new proxies comparing to usual proxies based on
#DNU pattern that
they guarantee a clear separation between meta-levels, i.e. even if
you send #doesNotUnderstand:
message to a proxy, this message will be trapped and handled by
handler as any other.



Yes, and the cool thing is that proxies can intercept ALL messages, not only those that are not understood. Hence, you don't need to subclass from ProtoObject or nil.
In addition (I think, I didn't measure) that they are faster because they don't need to the method lookup until getting to the dnu..but I am not sure about this last one.

Another problem with the DNU is what Igor say, you are mixing both things: error handling and message trapping. So...when a proxy receives DNU, how do you know if it was a real dnu or because it needs to trap the message?

Implementing method wrappers on top of such proxies is a matter of 5 minutes as much as I can see. In fact, in the paper I "implement" method wrappers as an example.

You can take a look by

Gofer new
squeaksource: 'Marea';
package: 'GhostProxies';
package: 'GhostProxiesTests';
load.

But remember it is just a prototype ;)

The paper is almost finish...

cheers


--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Mariano Martinez Peck
Ahhh and the difference with MethodWrappers (at least with the implementation that is in the Pharo image)

- MethodWrapper intercepts both things: 1) messages sent to the object (as if it were a compiled method), and 2) method execution
MyClass at: #foo put: MyMethodWrapper.
(MyClass methodAt: #foo) literals.   --->>  1)
MyClass new foo   ---->>  2)

1) is done using #dnu  and 2) using #run:with:in:

the problem is that the method wrapper is a subclass from Object, so there are 375 methods (Object methodDict size) that will be understood by the proxy itself instead of trapping the message. Ok, you can subclass from ProtoObject, that would be better (ProtoObject methodDict size -> 38 ). But still, even subclassing from nil, it is not stratified.

(MyClass methodAt: #foo)  blahBlah will try to trap the message instead of raise a MNU.

I don't know what do you need for your case, if both things 1) and 2). If it is only 2) then there is few advantages with our implemetnation. If you need both, then yes, I would take a look.

 cheers

mariano

On Thu, May 5, 2011 at 9:59 AM, Mariano Martinez Peck <[hidden email]> wrote:


On Thu, May 5, 2011 at 4:30 AM, Igor Stasenko <[hidden email]> wrote:
On 5 May 2011 01:59, Johan Fabry <[hidden email]> wrote:
>
> On 04 May 2011, at 17:30, Stéphane Ducasse wrote:
>
>>
>> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).
>
>
> Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers?
>

Sorry i'm not familiar with methodwrappers.

The basic model is separation of proxy and handler. Proxy acts only as
a message trap,
while handler is actually responsible for handling messages trapped by proxy.

Mariano builds on top of that, because he wants to replace classes
and/or methods with proxies,
and this requires a special handling (class proxy should obey
VM-specific Behavior format,
and method proxy should implement #run:in:as: when installed in method
dictionary ).

So, i guess that proxies which representing compiled methods could act
similar to method wrappers.
But of course you still have to implement all intall/deinstall
management et al..

The only advantage of new proxies comparing to usual proxies based on
#DNU pattern that
they guarantee a clear separation between meta-levels, i.e. even if
you send #doesNotUnderstand:
message to a proxy, this message will be trapped and handled by
handler as any other.



Yes, and the cool thing is that proxies can intercept ALL messages, not only those that are not understood. Hence, you don't need to subclass from ProtoObject or nil.
In addition (I think, I didn't measure) that they are faster because they don't need to the method lookup until getting to the dnu..but I am not sure about this last one.

Another problem with the DNU is what Igor say, you are mixing both things: error handling and message trapping. So...when a proxy receives DNU, how do you know if it was a real dnu or because it needs to trap the message?

Implementing method wrappers on top of such proxies is a matter of 5 minutes as much as I can see. In fact, in the paper I "implement" method wrappers as an example.

You can take a look by

Gofer new
squeaksource: 'Marea';
package: 'GhostProxies';
package: 'GhostProxiesTests';
load.

But remember it is just a prototype ;)

The paper is almost finish...

cheers


--



--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Stéphane Ducasse
In reply to this post by Panu Suominen

On May 5, 2011, at 9:46 AM, Panu Suominen wrote:

> 2011/5/5 Stéphane Ducasse <[hidden email]>:
>> why copy is not enough for you?
>> and you redefine postCopy to copy the instance variables?
>
> Because it would involve manual labour for any object that is going to
> be used in business logic. This would create artificial requirement
> that is easily forgotten. However first try-out of this approach used
> postCopy in domain objects.
>
> I thought that copyTwoLevel is going to be deprecated because it is
> too specific. However I am not sure whether this is actually true. It
> depends how often copying objects is necessary.
> The deprecation is not a problem. I can easily just create utility
> class that copies objects like copyTwoLevel.

why not putting the method in your domain object root?

>
> --
> Panu
>


Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

Panu Suominen
2011/5/5 Stéphane Ducasse <[hidden email]>:
> why not putting the method in your domain object root?

When doing things like this domain object could return objects out
side of the domain object hierarchy and they should be copied. Most
notably collections. Also I think that if copyTwoLevel it is too
spesific for object it is too spesific for domain objects. That does
not matter now because the approach was flawed...

Original idea was to copy only two levels to avoid too much work and
only do more copying when necessary. Two levels where copied because
this would handle situations where objects internal state is changed.
More levels would get copied when the proxied object would return new
values. Thus the proxy had following code.

doesNotUnderstand: aMessage
        | result |
        accumulator add: aMessage -> originalObject.
        result := aMessage sendTo: copyObject.
        ^ (result isLiteral)
                ifTrue: [ result ]
                ifFalse: [ transaction proxyFor: result ]

And copyObject is initialized using originalObject copyTwoLevel.

However this just is not a proper solution because there might be
calls that dive deeply in the structure and alter objects that have
not been copied yet (they are lower than second level from object the
message is send). But deep copy alone won't handle this either. After
deep copying it is hard to say which objects where changed and which
were not.

--
Panu

Reply | Threaded
Open this post in threaded view
|

Re: Object>>copyTwoLevel

jfabry
In reply to this post by Mariano Martinez Peck

OK thanks Igor and Mariano. We'll consider it, send the paper when it is finished ;-)
 
On 05 May 2011, at 04:10, Mariano Martinez Peck wrote:

Ahhh and the difference with MethodWrappers (at least with the implementation that is in the Pharo image)

- MethodWrapper intercepts both things: 1) messages sent to the object (as if it were a compiled method), and 2) method execution
MyClass at: #foo put: MyMethodWrapper.
(MyClass methodAt: #foo) literals.   --->>  1)
MyClass new foo   ---->>  2)

1) is done using #dnu  and 2) using #run:with:in:

the problem is that the method wrapper is a subclass from Object, so there are 375 methods (Object methodDict size) that will be understood by the proxy itself instead of trapping the message. Ok, you can subclass from ProtoObject, that would be better (ProtoObject methodDict size -> 38 ). But still, even subclassing from nil, it is not stratified.

(MyClass methodAt: #foo)  blahBlah will try to trap the message instead of raise a MNU.

I don't know what do you need for your case, if both things 1) and 2). If it is only 2) then there is few advantages with our implemetnation. If you need both, then yes, I would take a look.

 cheers

mariano

On Thu, May 5, 2011 at 9:59 AM, Mariano Martinez Peck <[hidden email]> wrote:


On Thu, May 5, 2011 at 4:30 AM, Igor Stasenko <[hidden email]> wrote:
On 5 May 2011 01:59, Johan Fabry <[hidden email]> wrote:
>
> On 04 May 2011, at 17:30, Stéphane Ducasse wrote:
>
>>
>> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3).
>
>
> Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers?
>

Sorry i'm not familiar with methodwrappers.

The basic model is separation of proxy and handler. Proxy acts only as
a message trap,
while handler is actually responsible for handling messages trapped by proxy.

Mariano builds on top of that, because he wants to replace classes
and/or methods with proxies,
and this requires a special handling (class proxy should obey
VM-specific Behavior format,
and method proxy should implement #run:in:as: when installed in method
dictionary ).

So, i guess that proxies which representing compiled methods could act
similar to method wrappers.
But of course you still have to implement all intall/deinstall
management et al..

The only advantage of new proxies comparing to usual proxies based on
#DNU pattern that
they guarantee a clear separation between meta-levels, i.e. even if
you send #doesNotUnderstand:
message to a proxy, this message will be trapped and handled by
handler as any other.



Yes, and the cool thing is that proxies can intercept ALL messages, not only those that are not understood. Hence, you don't need to subclass from ProtoObject or nil.
In addition (I think, I didn't measure) that they are faster because they don't need to the method lookup until getting to the dnu..but I am not sure about this last one.

Another problem with the DNU is what Igor say, you are mixing both things: error handling and message trapping. So...when a proxy receives DNU, how do you know if it was a real dnu or because it needs to trap the message?

Implementing method wrappers on top of such proxies is a matter of 5 minutes as much as I can see. In fact, in the paper I "implement" method wrappers as an example.

You can take a look by

Gofer new
squeaksource: 'Marea';
package: 'GhostProxies';
package: 'GhostProxiesTests';
load.

But remember it is just a prototype ;)

The paper is almost finish...

cheers


--



--
Mariano
http://marianopeck.wordpress.com


--
Johan Fabry   
PLEIAD Lab - Computer Science Department (DCC) - University of Chile