I started with this basic abstract class for Geometry:
@Serializable
abstract const class Geometry {
const Str type
new make( Str type, |This| f ) {
this.type = type
f(this)
}
}
Then I extended this abstract class to model a Point:
const class GeoPoint : Geometry {
const Decimal[] coordinates
new make( |This| f ) : super( "Point", f ) { }
Decimal? longitude() { coordinates.size >= 1 ? coordinates[ 0 ] : null }
Decimal? latitude() { coordinates.size >= 2 ? coordinates[ 1 ] : null }
Decimal? altitude() { coordinates.size >= 3 ? coordinates[ 2 ] : null }
}
This compiles Ok and works fine in a simple scenario, but if I try to use via IoC, I get this error message:
[err] [afBedSheet] afIoc::IocErr - Field myPod::GeoPoint.coordinates was not set by ctor sys::Void make(|sys::This->sys::Void| f)
Causes:
afIoc::IocErr - Field myPod::GeoPoint.coordinates was not set by ctor sys::Void make(|sys::This->sys::Void| f)
sys::FieldNotSetErr - myPod::GeoPoint.coordinates
IoC Operation Trace:
[ 1] Autobuilding 'GeoPoint'
[ 2] Creating 'GeoPoint' via ctor autobuild
[ 3] Instantiating myPod::GeoPoint via Void make(|This->Void| f)...
Stack Trace:
afIoc::IocErr : Field myPod::GeoPoint.coordinates was not set by ctor sys::Void make(|sys::This->sys::Void| f)
I presume it is because the constructor has another parameter, apart from |This| f
. Is there a better way to write the Geology and GeoPoint classes, please?
For serialisation, you need an it-block ctor called make()
. But that doesn't stop you from defining your own ctors. I would keep the two ctors separate, as a means of separating concerns.
For a simple data type, I would normally pass fields values as ctor parameters.
This would leave the objects looking like this:
@Serializable
abstract const class Geometry {
const Str type
// for serialisation
new make(|This| f) {
f(this)
}
new makeWithType(Str type) {
this.type = type
}
}
@Serializable
const class GeoPoint : Geometry {
const Decimal[] coordinates
// for serialisation
new make(|This| f) : super.make(f) { }
new makeWithCoors(Decimal[] coordinates) : super.makeWithType("Point") {
this.coordinates = coordinates
}
}
Fantom serialisation will use the make()
ctor and you can use the makeWithCoors()
ctor - like this:
point1 := GeoPoint([1d, 2d]) // or
point2 := GeoPoint.makeWithCoors([1d, 2d])
Note that you don't have to name the ctor as Fantom will work it out from the arguments.
Also note that your own ctors may be named anything, but by convention they start with makeXXXX()
.
To then autobuild a GeoPoint
with IoC do this:
point := (GeoPoint) registry.autobuild(GeoPoint#, [[1d, 2d]])
that would then use the makeWithCoors()
ctor.