FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Custom load/save of classes with inheritance

 
Post new topic   Reply to topic     Forum Index -> Doost
View previous topic :: View next topic  
Author Message
baxissimo



Joined: 23 Oct 2006
Posts: 241
Location: Tokyo, Japan

PostPosted: Sun Jun 29, 2008 10:58 pm    Post subject: Custom load/save of classes with inheritance Reply with quote

The custom load save doesn't seem to work so nicely in the presence of inheritance. Did you have any ideas about how to handle this?

Right now I can get something like this to work, but it's not so clean or easy I don't think:

Code:

unittest { testCase.traces.execute("load/dump - custom loaders/dumpers w/ inheritance", {
    TransparentClass input;
    string output;

    //------ TransparentClass ----------
    auto descr = serializer.global().typeDescription!(TransparentClass);
    descr.loader =
        delegate bool (ref TransparentClass value, serializer.Archive archive) {
            if (!value) value = new TransparentClass;

            void check(bool res) {
                if (!res) throw new Exception("Format for my class is not correct!");
            }

            skip(archive.storage, archive.defSkip.p_skip);
           
            check(archive.traverse(value.a));
            check(skip(archive.storage, "-") != 0);
            check(archive.traverse(value.b));
            check(skip(archive.storage, "-") != 0);
            check(archive.traverse(value.c));
            check(skip(archive.storage, "-") != 0);

            if (auto peek = archive.typeDescription!(Base)) {
                auto bvalue = cast(Base)value;
                if (peek.loader !is null) return peek.loader(bvalue, archive);
            }

            return true;
        };

    descr.dumper =
        delegate bool (ref TransparentClass value, serializer.Archive archive)
        {
            archive.storage.put(format("%d-%f-\"%s\"-", value.a,value.b,value.c));
            if (auto peek = archive.typeDescription!(Base)) {
                auto bvalue = cast(Base)value;
               if (peek.dumper !is null) return peek.dumper(bvalue, archive);
            }
            return true;
        };
   
    //------ Base ----------
    auto descrb = serializer.global().typeDescription!(Base);
    descrb.loader =
        delegate bool (ref Base value, serializer.Archive archive)
        {
            trace("Base loader");
            if (!value) value = new Base;

            void check(bool res) {
                if (!res) throw new Exception("Format for my class is not correct!");
            }

            skip(archive.storage, archive.defSkip.p_skip);
           
            check(archive.traverse(value.x));
            check(skip(archive.storage, "-") != 0);
            check(archive.traverse(value.y));

            return true;
        };

    descrb.dumper =
        delegate bool (ref Base value, serializer.Archive archive)
        {
            trace("Base dumper");
            archive.storage.put(format("%d-%d", value.x, value.y));
            return true;
        };
    //------

    input = new TransparentClass(1,2,"narf",5,10);
    output = serializer.dump(input);
    trace(output);
    assert(output == "1-2.000000-\"narf\"-5-10");
    assert(serializer.load!(TransparentClass)(output) == input);

});}


It's not good because it will not work if the Base class doesn't also have custom loader/dumper methods defined. I think at most the custom load/dump routine should just have to call one function like archive.loadBase!(Base)(value) or something like that.

What do you think?
Back to top
View user's profile Send private message
aarti_pl



Joined: 25 Jul 2006
Posts: 28

PostPosted: Mon Jun 30, 2008 1:27 pm    Post subject: Reply with quote

Why not to use:

Code:
auto bvalue = cast(Base)value;
check(archive.traverse(bvalue));


instead of:
Code:
if (auto peek = archive.typeDescription!(Base)) {
  auto bvalue = cast(Base)value;
  if (peek.loader !is null) return peek.loader(bvalue, archive);
}


?

In that case you don't need custom loader/dumper for base class. But if they are defined they will be still used...

Maybe I am missing something here? Please elaborate...
Back to top
View user's profile Send private message
baxissimo



Joined: 23 Oct 2006
Posts: 241
Location: Tokyo, Japan

PostPosted: Mon Jun 30, 2008 3:30 pm    Post subject: Reply with quote

Yeh, that will probably work. Good idea.

I think part of my hang up was that the example you have of a custom loader unconditionally constructs a new object. Is it guaranteed to be safe to just do what I did there and only construct if the value is null?
Back to top
View user's profile Send private message
aarti_pl



Joined: 25 Jul 2006
Posts: 28

PostPosted: Mon Jun 30, 2008 4:38 pm    Post subject: Reply with quote

Hmm. Normally the value should always be null. It is only declared in load() function and instantiated later. But I can imagine that the class which contains TransparentClass can initialize TransparentClass during construction. In that case it won't be null. And that's why I think that for deserialization it will be safer to always construct class.

(In fact here occurs shortage of D. It would be handy to create class without using constructor at all. In deserialization constructor is completely not necessary and even disturbing.)
Back to top
View user's profile Send private message
baxissimo



Joined: 23 Oct 2006
Posts: 241
Location: Tokyo, Japan

PostPosted: Mon Jun 30, 2008 5:41 pm    Post subject: Reply with quote

aarti_pl wrote:
Hmm. Normally the value should always be null. It is only declared in load() function and instantiated later. But I can imagine that the class which contains TransparentClass can initialize TransparentClass during construction. In that case it won't be null. And that's why I think that for deserialization it will be safer to always construct class.


I'm not getting it. The way it is now, if you set a loader for Base, and you are deserializing something that's actually Base, then Base needs to be constructed in that loader. Ok. But if you're actually deserializing a Derived then Derived's loader will construct a Derived, and then call Base's loader to fill in the missing fields. So in that case Base should *not* construct a new object.

aarti_pl wrote:
(In fact here occurs shortage of D. It would be handy to create class without using constructor at all. In deserialization constructor is completely not necessary and even disturbing.)


Object.factory(classname)? Or are you thinking of something else?
Back to top
View user's profile Send private message
aarti_pl



Joined: 25 Jul 2006
Posts: 28

PostPosted: Tue Jul 01, 2008 1:54 pm    Post subject: Reply with quote

I mean situation like below:

Code:
class SuperType {
  TransparentClass tc;

  this() {
    tc = new TransparentClass;
  }
}


In above case constructor works completely unnecessary - tc will be restored from deserialization not constructed in constructor. I would like to have possibility to construct object without starting constructor - just proper memory allocation.

In case of "Object.factory(classname)" you will need also default constructor to create class.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Doost All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group