Reading the serialization page and trying the following example, there is, I think, quite a few explanation missing on the page, regarding what exactly happen when deserializing an object: call to make() or need to have a defVal value define... Is this correct?
The page on construction using it-block, with-block ... quite explicitly shows what happens under the cover... But I have the feeling for serialization, there are some steps missing in the doc.
To explain, I just used the following example, one using a non const class and another one using a const class...
@Serializable
class Point
{
Int x; Int y
override Str toStr() { "$x,$y" }
}
@Serializable
class cPoint
{
const Int x; const Int y
override Str toStr() { "$x,$y" }
new make(|This| f) { f(this) }
}
class Ser
{
static Void main()
{
StrBuf buf := StrBuf()
p := Point { x = 1; y = 2 }
buf.out.writeObj(p, ["indent":2])
strP := buf.toStr
echo(strP)
p = strP.in.readObj()
echo(p)
buf.clear
cp := cPoint { x = 1; y = 2 }
buf.out.writeObj(cp, ["indent":2])
strCP := buf.toStr
echo(strCP)
cp = strCP.in.readObj()
echo(cp)
}
}
I would have thought that because an it-block make is define, the serialization will use it but does not seem to be true...
I cannot fine anywhere in the doc talking about this defVal...
KevinKelleyThu 4 Mar 2010
That error message gets me too. It's complaining about this constructor:
new make(|This| f) { f(this) }
and the problem is, the f parameter doesn't have a default value:
new make(|This| f := null) { f?.call(this) }
The reason it needs a default value is, when you de-serialize an object, fantom will first construct a default object, then load it with the serialized data. But if there's no default constructor new make() , or else no default params for some constructor, then fantom can't make a default object. Thus the error.
lbertrandThu 4 Mar 2010
But in this case that means that the fields have to be nullable!
To be clearer, it is ok in this example as Int default to 0, but if you have a Str, which default to null that will not work!
But using the construction mechanism with it-blocks, no need of doing this... Is this not possible to have the deserialization process using the construction principle of it-blocks?
tacticsThu 4 Mar 2010
new make(|This| f := null) { f?.call(this) }
Kevin, I think you mean new make(|This|? f := null) { f?.call(this) } (with the nullable |This|? type.
KevinKelleyThu 4 Mar 2010
@tactics: Yes, that's what I meant to say, sorry.
@lbertrand: right, but I don't see how to get around it: when you define a class, encapsulation should mean that, you guarantee that once an object of the class is constructed, it's in a consistent state. But, if you have a it-block, then you're allowing outside users to be responsible for setting your state. So, there would have to be some way of ensuring that, even if a user of the class forgets to initialize a field in the it-block, the created object is still self-consistent.
I think this issue is being discussed, but right now I can't find a reference. It's sort of related to #987 I think.
jodastephenFri 5 Mar 2010
As far as I know, deserialization in Fantom is still extralinguistic like Java. And this is a very Bad Thing (close to top of my kist of current Fantom problems).
There are a variety of solutions, but it essential that some application code can be invoked to check and validate deserialized code. It would be preferable if that was a standard constructor rather than additional code.
brianFri 5 Mar 2010
The way it works today is very simple:
calls sys::Type.make (if you look at fandoc for that method it explains defVal issue)
assigns const fields with their values
So today you will need to make sure your it-block is nullable and probably make your fields nullable.
The way it should work is that serialization should set your const fields thru the it-block passed to your constructor. That would give you the proper hooks to verify the deserialization and would cleanly hook into the runtime nullable checks. This something I'm planning to tackle when I get to ticket #832.
The issue of how const immutability and nullable types interact is perhaps one of the most novel features of Fantom. But we still have a few things left to do to make it all works smoothly.
lbertrand Thu 4 Mar 2010
Reading the serialization page and trying the following example, there is, I think, quite a few explanation missing on the page, regarding what exactly happen when deserializing an object: call to make() or need to have a defVal value define... Is this correct?
The page on construction using it-block, with-block ... quite explicitly shows what happens under the cover... But I have the feeling for serialization, there are some steps missing in the doc.
To explain, I just used the following example, one using a non const class and another one using a const class...
I have the following error
I would have thought that because an it-block make is define, the serialization will use it but does not seem to be true...
I cannot fine anywhere in the doc talking about this defVal...
KevinKelley Thu 4 Mar 2010
That error message gets me too. It's complaining about this constructor:
and the problem is, the
f
parameter doesn't have a default value:The reason it needs a default value is, when you de-serialize an object, fantom will first construct a
default
object, then load it with the serialized data. But if there's no default constructornew make()
, or else no default params for some constructor, then fantom can't make a default object. Thus the error.lbertrand Thu 4 Mar 2010
But in this case that means that the fields have to be nullable!
To be clearer, it is ok in this example as Int default to 0, but if you have a Str, which default to null that will not work!
But using the construction mechanism with it-blocks, no need of doing this... Is this not possible to have the deserialization process using the construction principle of it-blocks?
tactics Thu 4 Mar 2010
Kevin, I think you mean
new make(|This|? f := null) { f?.call(this) }
(with the nullable|This|?
type.KevinKelley Thu 4 Mar 2010
@tactics: Yes, that's what I meant to say, sorry.
@lbertrand: right, but I don't see how to get around it: when you define a class, encapsulation should mean that, you guarantee that once an object of the class is constructed, it's in a consistent state. But, if you have a it-block, then you're allowing outside users to be responsible for setting your state. So, there would have to be some way of ensuring that, even if a user of the class forgets to initialize a field in the it-block, the created object is still self-consistent.
I think this issue is being discussed, but right now I can't find a reference. It's sort of related to #987 I think.
jodastephen Fri 5 Mar 2010
As far as I know, deserialization in Fantom is still extralinguistic like Java. And this is a very Bad Thing (close to top of my kist of current Fantom problems).
There are a variety of solutions, but it essential that some application code can be invoked to check and validate deserialized code. It would be preferable if that was a standard constructor rather than additional code.
brian Fri 5 Mar 2010
The way it works today is very simple:
sys::Type.make
(if you look at fandoc for that method it explains defVal issue)So today you will need to make sure your it-block is nullable and probably make your fields nullable.
The way it should work is that serialization should set your const fields thru the it-block passed to your constructor. That would give you the proper hooks to verify the deserialization and would cleanly hook into the runtime nullable checks. This something I'm planning to tackle when I get to ticket #832.
The issue of how const immutability and nullable types interact is perhaps one of the most novel features of Fantom. But we still have a few things left to do to make it all works smoothly.