I have a feeling the current Serialization Docs along with `http://fantom.org/sidewalk/topic/1005#c7344` and `http://fantom.org/sidewalk/topic/832` don't tell the whole story...
They all suggest that a non-nullable it block works fine when it comes to serialization, and indeed the following works fine:
@Serializable
class Dude {
const Int x; const Int y
new make(|This| f) { f.call(this) }
static Void main(Str[] args) {
dude := Dude{x=3; y=4}
StrBuf().out.writeObj(dude)
}
}
However, the addition of skipDefaults when serializing results in:
sys::Err: Type missing "make" or "defVal" slots: afalife::Dude
But making the it block nullable makes everything okay again:
@Serializable
class Dude {
const Int x; const Int y
new make(|This|? f := null) { f?.call(this) }
static Void main(Str[] args) {
dude := Dude{x=3; y=4}
StrBuf().out.writeObj(dude, ["skipDefaults" : true])
}
}
Could the example in the Serialization Docs be updated to show a nullable it block, for I feel this is a trap for young players!
Cheers.
SlimerDudeSat 25 Feb 2012
( I had a feeling this was going to be a multi-part post! )
Updating the example above to use a Simple Serializable type is fine:
@Serializable{simple=true}
const class Pie {
const Int wot
new make(Int wot) { this.wot = wot }
override Str toStr() { "$wot" }
static Pie fromStr(Str str) { Pie(str.toInt) }
}
@Serializable
const class Sausage {
const Pie x; const Pie y
new make(|This|? f := null) { f?.call(this) }
static Void main(Str[] args) {
sausage := Sausage{x=Pie(3); y=Pie(4)}
StrBuf().out.writeObj(sausage)
}
}
The solution is to move the it block to the end of the parameter list:
new make(Str name := "Cow", |This|? f := null) : super(name) { ... }
On digging through this forum, it's mentioned briefly in passing in `http://fantom.org/sidewalk/topic/832#c7551`
(By the way, these aren't random examples I've been trying out, I'm narrowing down the reasons why I can't pass messages between Actors in an AI app I'm porting over.)
Obviously Fantom serialization is rather powerful and ingrained in the language from the core... and I can't help thinking that more meaningful Err messages and a solid list of what you can and can't do in the documentation, would go a long way in helping us untrained Newbies!
KevinKelleySat 25 Feb 2012
Looking in src/sys/java/fanx/ObjEncoder.java I see there's a direct call to FanObj.typeof(obj).make() when skipDefaults is true... I think the recent changes to Fantom constructors may cause that to fail in some situations...
brianSat 25 Feb 2012
Promoted to ticket #1787 and assigned to brian
What we have here is a bad interaction between two of Fantom's most complex features: serialization and const classes. I'll need to some spend some time looking at your use cases and maybe tightening up the serialization semantics for const classes.
Regarding your note that you are doing this for Actors - if you have const classes, you don't need serialization. You just pass the messages by reference. In fact I don't think I've ever used serialization based messages, and I'm wondering if that was a mistake and we should force all messages to be const (it would make serialization to Str a manual process).
KevinKelleySat 25 Feb 2012
force all messages to be const
I hope not; I find a lot of times const is too onerous, but serializable gives me an out. For instance any structure that's not a DAG -- if you need both forward and back links, it's either impossible, or too hard, to make the elements be const. But you can serialize by fixing up the links yourself...
brianSat 25 Feb 2012
Okay good to know what some people use that mechanism
SlimerDudeSat 25 Feb 2012
Sweet, I'm well pleased I've found some nefarious middle ground and I'm not just being a pain!
Regarding your note that you are doing this for Actors - if you have const classes, you don't need serialization.
This I don't quite understand. When I tried passing my classes between Actors I got Errs, from the docs I assumed they'd be serialization Errs and wrote the test cases; where I got (similar?) Errs. After fixing up the serialization test cases, my main code then started working! (For F1.0.60 that is, I make heavy use of Ranges!)
brianSat 25 Feb 2012
This I don't quite understand. When I tried passing my classes between Actors I got Errs
If your class is const it is just passed by reference - that is the optimal way to do messaging because its really efficient and fast. The check is actually Obj.isImmutable (since List, Maps, and Funcs have special rules).
brianWed 18 Oct 2017
Ticket cancelled
Re-reading this, I think it was a duplicate of 2644
SlimerDudeWed 18 Oct 2017
Agreed, most of it is a duplicate of `#2644`, but a quick note on the problem in the 3rd comment...
The comment presents this code:
@Serializable
const class Flying { }
@Serializable
const class Sausage : Flying {
const Int oops := 66
new make(|This|? f := null, Str? name := null) : super.make() {
f?.call(this)
}
}
class Example {
Void main() {
Buf().writeObj( Sausage() ).flip.readObj
}
}
And gives this error when run:
sys::ReadonlyErr: Cannot set const field Ser_0::Sausage.oops
The issue is the ctor of Sausage which takes an it-block arg as the first parameter. If you switch the parameters around, so the it-block is last, then everything works fine:
new make(Str? name := null, |This|? f := null) : super.make() { ... }
While experienced Fantom developers will naturally place the it-block at the end of the parameter list as per `#832`, my concern is that this is not obvious to less experienced Fantom developers. (Well, it wasn't obvious to me when I wrote this topic!)
So I have 2 questions really:
Is there a valid reason to not put an it-block parameter at the end of the parameter list?
If not, then could the compiler spit out a warning (or error?) if an it-block parameter is not at the end of a ctor param list?
brianFri 20 Oct 2017
It was not the intention that serialization worked with anything other than a constructor that took a single it-block. The fact that any of those work is a side effect of perhaps not enough error checking
SlimerDude Sat 25 Feb 2012
I have a feeling the current Serialization Docs along with `http://fantom.org/sidewalk/topic/1005#c7344` and `http://fantom.org/sidewalk/topic/832` don't tell the whole story...
They all suggest that a non-nullable
it
block works fine when it comes to serialization, and indeed the following works fine:However, the addition of
skipDefaults
when serializing results in:sys::Err: Type missing "make" or "defVal" slots: afalife::Dude
But making the
it
block nullable makes everything okay again:Could the example in the Serialization Docs be updated to show a nullable
it
block, for I feel this is a trap for young players!Cheers.
SlimerDude Sat 25 Feb 2012
( I had a feeling this was going to be a multi-part post! )
Updating the example above to use a Simple Serializable type is fine:
But again, serializing with
skipDefaults
gives:sys::FieldNotSetErr: afalife::Sausage.x
Only this time I'm not sure what's on or how to overcome it (well, besides from not using
skipDefaults
!SlimerDude Sat 25 Feb 2012
While I'm on a roll of Fantom language abuse, here's another serialization example I thought would work but doesn't:
gives
The solution is to move the
it
block to the end of the parameter list:On digging through this forum, it's mentioned briefly in passing in `http://fantom.org/sidewalk/topic/832#c7551`
(By the way, these aren't random examples I've been trying out, I'm narrowing down the reasons why I can't pass messages between Actors in an AI app I'm porting over.)
Obviously Fantom serialization is rather powerful and ingrained in the language from the core... and I can't help thinking that more meaningful
Err
messages and a solid list of what you can and can't do in the documentation, would go a long way in helping us untrained Newbies!KevinKelley Sat 25 Feb 2012
Looking in src/sys/java/fanx/ObjEncoder.java I see there's a direct call to
FanObj.typeof(obj).make()
when skipDefaults is true... I think the recent changes to Fantom constructors may cause that to fail in some situations...brian Sat 25 Feb 2012
Promoted to ticket #1787 and assigned to brian
What we have here is a bad interaction between two of Fantom's most complex features: serialization and const classes. I'll need to some spend some time looking at your use cases and maybe tightening up the serialization semantics for const classes.
Regarding your note that you are doing this for Actors - if you have const classes, you don't need serialization. You just pass the messages by reference. In fact I don't think I've ever used serialization based messages, and I'm wondering if that was a mistake and we should force all messages to be const (it would make serialization to Str a manual process).
KevinKelley Sat 25 Feb 2012
I hope not; I find a lot of times
const
is too onerous, but serializable gives me an out. For instance any structure that's not a DAG -- if you need both forward and back links, it's either impossible, or too hard, to make the elements beconst
. But you can serialize by fixing up the links yourself...brian Sat 25 Feb 2012
Okay good to know what some people use that mechanism
SlimerDude Sat 25 Feb 2012
Sweet, I'm well pleased I've found some nefarious middle ground and I'm not just being a pain!
This I don't quite understand. When I tried passing my classes between Actors I got Errs, from the docs I assumed they'd be serialization Errs and wrote the test cases; where I got (similar?) Errs. After fixing up the serialization test cases, my main code then started working! (For F1.0.60 that is, I make heavy use of Ranges!)
brian Sat 25 Feb 2012
If your class is const it is just passed by reference - that is the optimal way to do messaging because its really efficient and fast. The check is actually
Obj.isImmutable
(since List, Maps, and Funcs have special rules).brian Wed 18 Oct 2017
Ticket cancelled
Re-reading this, I think it was a duplicate of 2644
SlimerDude Wed 18 Oct 2017
Agreed, most of it is a duplicate of `#2644`, but a quick note on the problem in the 3rd comment...
The comment presents this code:
And gives this error when run:
The issue is the ctor of
Sausage
which takes an it-block arg as the first parameter. If you switch the parameters around, so the it-block is last, then everything works fine:While experienced Fantom developers will naturally place the it-block at the end of the parameter list as per `#832`, my concern is that this is not obvious to less experienced Fantom developers. (Well, it wasn't obvious to me when I wrote this topic!)
So I have 2 questions really:
brian Fri 20 Oct 2017
It was not the intention that serialization worked with anything other than a constructor that took a single it-block. The fact that any of those work is a side effect of perhaps not enough error checking