www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - object.factory with template classes for serializing subclasses

reply "timotheecour" <thelastmammoth gmail.com> writes:
Is there a way to use Object.factory with template classes?
eg:
----
class A(T){
     T x;
}
auto a=Object.factory("A!int");
----
Right now this fails (returns null).

Use case:
If we had this, it would GREATLY simplify serialization (eg as in 
the orange library) by not having to manually register subclasses 
of a given class, eg:
class B{}
class C:B{int x;}
B c=new C;
right now with orange, we need to register class C before calling 
serialization. If something like Object.factory("A!int") worked, 
this step could be made automatic.
Sep 09 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-09-10 01:27, timotheecour wrote:
 Is there a way to use Object.factory with template classes?
 eg:
 ----
 class A(T){
      T x;
 }
 auto a=Object.factory("A!int");
 ----
 Right now this fails (returns null).

 Use case:
 If we had this, it would GREATLY simplify serialization (eg as in the
 orange library) by not having to manually register subclasses of a given
 class, eg:
 class B{}
 class C:B{int x;}
 B c=new C;
 right now with orange, we need to register class C before calling
 serialization. If something like Object.factory("A!int") worked, this
 step could be made automatic.

I don't understand how Object.factory could help with serializing. But what would help is if we did get proper runtime reflection. -- /Jacob Carlborg
Sep 09 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-09-11 07:57, Chris Cain wrote:

 Ah, I see now.

 Well regardless, it couldn't be done so conveniently/transparently
 because Serializable!B wouldn't exist in the binary unless it was
 actually created in code.

Hence proper runtime reflection is needed. I see no way out of this. -- /Jacob Carlborg
Sep 10 2012
prev sibling next sibling parent "timotheecour" <thelastmammoth gmail.com> writes:
 I don't understand how Object.factory could help with 
 serializing. But what would help is if we did get proper 
 runtime reflection.

All that'd be needed would be to have Object.factory working with templates, here's how: ---- unittest{ class A{} class B{int x;} A a=new B; auto c=serialize(a);//will serialize field "x", no need to register!B } auto serialize(T)(T a){ auto c=cast(SerializerBase)Object.factory("Serializer!("~typeid(a).to!string~").Serializer"); return c.serialize(a); } class SerializerBase{//could also be an interface auto serialize(Object a){} } class Serializer(T):SerializerBase{ auto serialize(Object a){ auto b=cast(T)a; foreach (name; __traits(allMembers, T)) { //now we have access to fields of most derived type; //we can get the fields from base class as well. } } } ---- I've left out details to focus on the key part. Deserialization is very similar. So the question is: is that technically impossible or not to enhance Object.factory in such ways?
Sep 10 2012
prev sibling next sibling parent "Chris Cain" <clcain uncg.edu> writes:
On Tuesday, 11 September 2012 at 03:18:40 UTC, timotheecour wrote:
 So the question is: is that technically impossible or not to 
 enhance Object.factory in such ways?

Unless someone else wants to correct me, I'm going to say technically impossible. Object.factory constructs a class at runtime given a string of the name of the class. Templates, however, are created at compile-time only. Basically, the compiler creates a new type every time it sees a template being used with new template arguments. So, as you can imagine, there doesn't exist any object for Object.factory to find at run time. Technically, code like this MIGHT be possible: --- import std.stdio; class MyB(T) { this() { writeln("hello MyB!(" ~ T.stringof ~")"); } } void main() { // create the actual type at compile-time Object b = Object.factory(MyB!int.classinfo.name); writeln("b = ", b); } --- In this case, the type (I'd think) is actually created at compile-time, so it actually exists so that Object.factory can get it. However, the code you showed in your previous post (just purely existing in the string) could never work.
Sep 10 2012
prev sibling next sibling parent "Chris Cain" <clcain uncg.edu> writes:
On Tuesday, 11 September 2012 at 03:18:40 UTC, timotheecour wrote:
 auto serialize(T)(T a){
     auto 
 c=cast(SerializerBase)Object.factory("Serializer!("~typeid(a).to!string~").Serializer");
     return c.serialize(a);
 }

Also, now that I think about it, why couldn't you do this? (it's equivalent): auto serialize(T)(T a) { auto c = cast(SerializerBase) new Serializer!T; return c.serialize(a); }
Sep 10 2012
prev sibling next sibling parent "timotheecour" <thelastmammoth gmail.com> writes:
 Also, now that I think about it, why couldn't you do this? 
 (it's equivalent):

 auto serialize(T)(T a) {
     auto c = cast(SerializerBase) new Serializer!T;
     return c.serialize(a);
 }

that won't work with my example: class A{} class B:A{int x;} A a=new B; auto c=serialize(a); => T is A, but we want B so that serialization includes field x.
Sep 10 2012
prev sibling parent "Chris Cain" <clcain uncg.edu> writes:
On Tuesday, 11 September 2012 at 04:47:11 UTC, timotheecour wrote:
 Also, now that I think about it, why couldn't you do this? 
 (it's equivalent):

 auto serialize(T)(T a) {
    auto c = cast(SerializerBase) new Serializer!T;
    return c.serialize(a);
 }

that won't work with my example: class A{} class B:A{int x;} A a=new B; auto c=serialize(a); => T is A, but we want B so that serialization includes field x.

Ah, I see now. Well regardless, it couldn't be done so conveniently/transparently because Serializable!B wouldn't exist in the binary unless it was actually created in code.
Sep 10 2012