www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - adding properties/methods to AA's?

reply Alex <CppCoder gmail.com> writes:
Ok, so I've got a property (I guess that's the proper term to use?) that I'd
like to be able to use with any AA declared as Variant[char[]].  For example,
I'd like to be able to do the following.

Variant[char[]] map;
ubyte []stream;

stream = map.serialize;
map.deserialize( stream );

int [int[]] map2;
stream = map.serialize; //invalid, int [int[]] does not have serialize property.

Is this even possible?  I'm sure someone will tell me to just write a function
such as ubyte []serialize( Variant[char[]]input ), and I'm aware this is an
option.  I just think the above looks a bit more slick.
Jul 22 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Alex wrote:
 Ok, so I've got a property (I guess that's the proper term to use?)
 that I'd like to be able to use with any AA declared as
 Variant[char[]].  For example, I'd like to be able to do the
 following.
 
 Variant[char[]] map; ubyte []stream;
 
 stream = map.serialize; map.deserialize( stream );
 
 int [int[]] map2; stream = map.serialize; //invalid, int [int[]] does
 not have serialize property.
 
 Is this even possible?  I'm sure someone will tell me to just write a
 function such as ubyte []serialize( Variant[char[]]input ), and I'm
 aware this is an option.  I just think the above looks a bit more
 slick.

You can do such a thing for regular arrays, but I don't think it works for dicts. http://www.digitalmars.com/d/arrays.html -- look for "Functions as Array Properties". There has long been murmuring about how that should be applied to all types, not just special-cased for arrays. Maybe someday, but as far as I know Walter has never weighed in on the idea of generalizing it. Also if you do go the route of making a "serialize" function, be aware that you can't do function overloading across modules in D, so you need to put all variations of the "serialize" function in the same file, or call each one explicitly by the module name where it is implemented, e.g.: static import varchar; // has serialize for Variant[char[]] static import intint; // has serialize for int[int[]] intint.serialize(map); varchar.serialize(map2); Or just give the functions different names to begin with. --bb
Jul 22 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:f81g6k$o47$1 digitalmars.com...

   static import varchar; // has serialize for Variant[char[]]
   static import intint; // has serialize for int[int[]]
   intint.serialize(map);
   varchar.serialize(map2);

 Or just give the functions different names to begin with.

Templates, man! Templates and IFTI!
Jul 23 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jarrett Billingsley wrote:
 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
 news:f81g6k$o47$1 digitalmars.com...
 
   static import varchar; // has serialize for Variant[char[]]
   static import intint; // has serialize for int[int[]]
   intint.serialize(map);
   varchar.serialize(map2);

 Or just give the functions different names to begin with.

Templates, man! Templates and IFTI!

... and a serialize() method in any user types that you want to use as keys/values in the map. Not sure what you were thinking of exactly, but a reasonable start to a templated map serializer function would be: ubyte[] serialize(VType,KType)(VType[KType] map) { ubyte[] ret = serialize(map.length) foreach(v,k; map) { ret ~= serialize(v); ret ~= serialize(k); } return ret; } You still need to have serialize() implemented somewhere for uint, VType and KType. So what you end up having to do is what writefln does. You can provide implementations of serialize() for all the built-ins in the serialization module, but non-built-ins have to implement a special member function (a la "toString" for writefln). That makes it difficult to extend the serialization system to include 3rd party objects not created with your serialization framework in mind. These are the kind of cross-cutting functionalities that become difficult to implement in a completely generic and extensible way without argument dependent (Koenig) lookup. Just thinking here -- I wonder if there might be some way to use CTFE/mixin type stuff to get around that. For instance instead of trying to call the 'serialize' method for a class, the template would try to call the function named "serialize_" ~ typeof(argument).stringof using a mixin. Then in your myclass.d module you define class MyClass, and also a serialize_MyClass(MyClass mc) {...}. --bb
Jul 23 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter Wrote:
 [...]
 You still need to have serialize() implemented somewhere for uint, VType 
 and KType.  So what you end up having to do is what writefln does. 
 You can provide implementations of serialize() for all the built-ins in 
 the serialization module, but non-built-ins have to implement a special 
 member function (a la "toString" for writefln).
 
 That makes it difficult to extend the serialization system to include 
 3rd party objects not created with your serialization framework in mind.
 

How about using __traits? You could serialize every primitive type normally and recursively serialize non-primitive members until they're broken down into component types.
Jul 24 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Robert Fraser wrote:
 Bill Baxter Wrote:
 [...]
 You still need to have serialize() implemented somewhere for uint, VType 
 and KType.  So what you end up having to do is what writefln does. 
 You can provide implementations of serialize() for all the built-ins in 
 the serialization module, but non-built-ins have to implement a special 
 member function (a la "toString" for writefln).

 That makes it difficult to extend the serialization system to include 
 3rd party objects not created with your serialization framework in mind.

How about using __traits? You could serialize every primitive type normally and recursively serialize non-primitive members until they're broken down into component types.

Yeh, that would be cool. But I think it can't really work 100% of the time without a little something extra, because sometimes there are members that shouldn't be saved -- a member that really is just caching something transient, for instance. --bb
Jul 24 2007
prev sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Alex skrev:
 Ok, so I've got a property (I guess that's the proper term to use?) that I'd
like to be able to use with any AA declared as Variant[char[]].  For example,
I'd like to be able to do the following.
 
 Variant[char[]] map;
 ubyte []stream;
 
 stream = map.serialize;
 map.deserialize( stream );
 
 int [int[]] map2;
 stream = map.serialize; //invalid, int [int[]] does not have serialize
property.
 
 Is this even possible?  I'm sure someone will tell me to just write a function
such as ubyte []serialize( Variant[char[]]input ), and I'm aware this is an
option.  I just think the above looks a bit more slick.

just write the function as ubyte[] serialize(Variant[char[]] input) and call it as: map.serialize(); // Note, the trailing pair of empty parentheses -- Oskar
Jul 23 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Oskar Linde wrote:
 Alex skrev:
 Ok, so I've got a property (I guess that's the proper term to use?) 
 that I'd like to be able to use with any AA declared as 
 Variant[char[]].  For example, I'd like to be able to do the following.

 Variant[char[]] map;
 ubyte []stream;

 stream = map.serialize;
 map.deserialize( stream );

 int [int[]] map2;
 stream = map.serialize; //invalid, int [int[]] does not have serialize 
 property.

 Is this even possible?  I'm sure someone will tell me to just write a 
 function such as ubyte []serialize( Variant[char[]]input ), and I'm 
 aware this is an option.  I just think the above looks a bit more slick.

just write the function as ubyte[] serialize(Variant[char[]] input) and call it as: map.serialize(); // Note, the trailing pair of empty parentheses

Hey you're right! I forgot that AA's work that way too. I had this little test function in my tests directory that didn't work at some point but now apparently it does: V get(V,K)(V[K] dict, K key, V def = V.init) { V* ptr = key in dict; return ptr? *ptr: def; } void main() { char[][int] i2s; i2s[1] = "Hello"; i2s[5] = "There"; writefln( i2s.get(1, "yeh") ); writefln( i2s.get(2, "default") ); writefln( i2s.get(1) ); } Boffo! --bb
Jul 23 2007
parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Bill Baxter wrote:
 Oskar Linde wrote:
 just write the function as ubyte[] serialize(Variant[char[]] input) 
 and call it as:

 map.serialize(); // Note, the trailing pair of empty parentheses

Hey you're right! I forgot that AA's work that way too. I had this little test function in my tests directory that didn't work at some point but now apparently it does: V get(V,K)(V[K] dict, K key, V def = V.init) { V* ptr = key in dict; return ptr? *ptr: def; } void main() { char[][int] i2s; i2s[1] = "Hello"; i2s[5] = "There"; writefln( i2s.get(1, "yeh") ); writefln( i2s.get(2, "default") ); writefln( i2s.get(1) ); } Boffo!

It has worked since DMD 0.178. Walter even refers to your post with this same example in the changelog. :) (The reason the above didn't work earlier was issues with IFTI and converting char[n] -> char[]) -- Oskar
Jul 24 2007