Proxy objects and controlling/monitoring access

Reiner Pope some at address.com
Fri Aug 17 18:42:19 PDT 2007


Reiner Pope wrote:
> Bill Baxter wrote:
>> This is something I've been thinking about lately.
>> Here's something I think is maybe a sort of language challenge akin to 
>> Andrei's "identity" template.  It's something that if you can do, 
>> opens up a lot of possibilities, even though it may not be that 
>> interesting by itself.
>>
>> Ok, so the challenge is, can you make a wrapper around a value that 
>> behaves identically to the value BUT also allows you to monitor each 
>> access?  The uses for this are many.  In particular observer patterns 
>> and the like often involve getting notifications when things change.
>>
>> One thing making me thing about this is the enthough.traits framework 
>> in Python that I've been looking at lately.  It's a very powerful 
>> paradigm for linking components together.  Basically when you use 
>> traits, instead of creating class memebers in the normal way you 
>> create them using something akin to 'my_int = new traits.Int'.  From 
>> there my_int basically looks exactly like a regular int to all users, 
>> the twist being that you can easily get a notification every time 
>> my_int changes.
>>
>> So can we do this in D?  I guess you might call this "identity with 
>> notifications"
>>
>> We can certainly do a lot of it using operator overloads.  But we 
>> can't do everything.  For instance, if you want to wrap a struct 
>> there's no way to emulate getting and setting of the struct's members 
>> without writing a specific wrapper that adds property get/set methods 
>> for each member of the wrapped struct.
>>
>>
>> --bb
> 
> I've written code which wraps a value in a class which derives from a 
> given interface. The interface is implemented by calling the value's 
> fields.  See the unit test of the attached mixininterface.d for 
> examples. In fact, the code isn't so messy, but it uses my own 
> collection of CTFE utils in my_metastrings.
> 
> I don't imagine it would be too hard to adapt my code to generate the 
> wrapper you want.
> 
> There are two behavioural differences, though:
> 
> 1.
> The generated class will have reference semantics, whether the backing 
> type is a value or a reference. This is partly a consequence of wrapping 
> it in an interface, but if I was trying to create the wrapper you 
> wanted, it would still be a problem. One solution would simply be to 
> check whether the type is a value or a reference type. If it's a value 
> type, implement the wrapper as a struct, if it's a reference, implement 
> the wrapper as a class. The alternative (but currently impossible) would 
> be to overload the class's opAssign for itself, emulating value semantics.
> 
> 2.
> Casting doesn't work properly. You don't retain the implementation's 
> position in the inheritance tree, so you can't cast back to it, etc.
> 
> 
>    -- Reiner
> 

After a bit of work, I've made a wrapper which will wrap a class and 
allow you to attach listeners for when the methods are called. But I'm 
not sure how to list the non-virtual overloads of a member; there 
doesn't seem to be anything in __traits to do that.

Code attached. I've attached a new version of my_metastrings.d which has 
a workaround to avoid listing 'this' as a class member.

   -- Reiner
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: wrapper.d
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20070818/5e6f060a/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: my_metastrings.d
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20070818/5e6f060a/attachment-0001.ksh>


More information about the Digitalmars-d mailing list