View previous topic :: View next topic |
Author |
Message |
baxissimo
Joined: 23 Oct 2006 Posts: 241 Location: Tokyo, Japan
|
Posted: Sun Jun 29, 2008 10:58 pm Post subject: Custom load/save of classes with inheritance |
|
|
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 |
|
|
aarti_pl
Joined: 25 Jul 2006 Posts: 28
|
Posted: Mon Jun 30, 2008 1:27 pm Post subject: |
|
|
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 |
|
|
baxissimo
Joined: 23 Oct 2006 Posts: 241 Location: Tokyo, Japan
|
Posted: Mon Jun 30, 2008 3:30 pm Post subject: |
|
|
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 |
|
|
aarti_pl
Joined: 25 Jul 2006 Posts: 28
|
Posted: Mon Jun 30, 2008 4:38 pm Post subject: |
|
|
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 |
|
|
baxissimo
Joined: 23 Oct 2006 Posts: 241 Location: Tokyo, Japan
|
Posted: Mon Jun 30, 2008 5:41 pm Post subject: |
|
|
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 |
|
|
aarti_pl
Joined: 25 Jul 2006 Posts: 28
|
Posted: Tue Jul 01, 2008 1:54 pm Post subject: |
|
|
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 |
|
|
|