When constructing new objects I tend to use it/'with'-blocks for construction to avoid complex constructor code or having multiple (java-like) constructors.
With nullables or value types I can just use a default constructor and an implicit with block
class A
{
Int x
Obj? data
new make() { echo("A") }
static Void main()
{
a := A { data = "hello"; x = 2 } // equivalent to A().with({data = "hello" })
echo("a=$a.data, x=$a.x")
}
}
however going to non-nullables
class A
{
Int x
Obj data
new make() { echo("A"); x=2 }
static Void main()
{
a := A { data = "hello"; x = 2 }
echo("a=$a.data, x=$a.x")
}
}
the compiler complains about not having all field assigned
Non-nullable field 'data' must be assigned in constructor 'make'
There are basically two options how to prevent this
changing the constructor to accept direct parameters (x, data)
changing the constructor to accept an initializing closure
class A {
Int x
Obj data
new make(|This|? f := null) { echo("A"); f?.call(this) }
static Void main()
{
a := A { data = "hello"; x = 2 }
echo("a=$a.data, x=$a.x")
}
}
The second option is much more convenient still not unsafe because I get sys::FieldNotSetErr on instantination (could be a compile error in the future).
With inheritance thrown into that problem the construction using a closure is a bit more flexible. I can decide if f will be executed first (in A constructor) or last (in B constructor) or both but that would lead to nasty side effects (f would be executed twice).
I find myself reluctant to write a parametric constructor for almost any object just because of non-nullable fields so I usually end up with nullable fields and using implicit .with-blocks. A design smell but I am lazy - hell, what could go wrong with a such simple class!
The question is couldn't be new make(|This|? f) { f?.call(this) } the default Obj constructor signature and implementation?
It makes no harm if unused - it is backward-compatible with the original Obj#make. It'd only effectivelly change .with blocks to .it blocks.
There may be performance implications but at first glance it seems that the compiler could just optimize out most of unused code.
What do you think?
go4Sun 8 Aug 2010
It's good idea.
this need default constructor is new make(|This|? f := null) {f?.call(this) } the constructor can't inherit.
AkcelistoSun 8 Aug 2010
I support this suggestion.
I tired to write in almost class new make(|This|? f := null) {f?.call(this) }. I use Fantom for fast prototyping and I often change list of fields in class. And I found that closure ctor is more handy then usual ctor.
rfeldmanSun 8 Aug 2010
Sounds excellent! +1
brianSun 8 Aug 2010
I think this is one of those cases where the developer has to explicitly design his or her class to use an it-block constructor or not.
Although the notion of easier boiler plate for ctors, hash, and equals for "value types" is something that we should eventually do. I just haven't seen a design I really like.
katox Sat 10 Jul 2010
When constructing new objects I tend to use
it
/'with'-blocks for construction to avoid complex constructor code or having multiple (java-like) constructors.With nullables or value types I can just use a default constructor and an implicit with block
however going to non-nullables
the compiler complains about not having all field assigned
There are basically two options how to prevent this
class A {
}
The second option is much more convenient still not unsafe because I get
sys::FieldNotSetErr
on instantination (could be a compile error in the future).With inheritance thrown into that problem the construction using a closure is a bit more flexible. I can decide if
f
will be executed first (in A constructor) or last (in B constructor) or both but that would lead to nasty side effects (f
would be executed twice).I find myself reluctant to write a parametric constructor for almost any object just because of non-nullable fields so I usually end up with nullable fields and using implicit
.with
-blocks. A design smell but I am lazy - hell, what could go wrong with a such simple class!The question is couldn't be
new make(|This|? f) { f?.call(this) }
the defaultObj
constructor signature and implementation?It makes no harm if unused - it is backward-compatible with the original
Obj#make
. It'd only effectivelly change.with
blocks to.it
blocks.There may be performance implications but at first glance it seems that the compiler could just optimize out most of unused code.
What do you think?
go4 Sun 8 Aug 2010
It's good idea.
this need default constructor is
new make(|This|? f := null) {f?.call(this) }
the constructor can't inherit.Akcelisto Sun 8 Aug 2010
I support this suggestion.
I tired to write in almost class
new make(|This|? f := null) {f?.call(this) }
. I use Fantom for fast prototyping and I often change list of fields in class. And I found that closure ctor is more handy then usual ctor.rfeldman Sun 8 Aug 2010
Sounds excellent! +1
brian Sun 8 Aug 2010
I think this is one of those cases where the developer has to explicitly design his or her class to use an it-block constructor or not.
Although the notion of easier boiler plate for ctors, hash, and equals for "value types" is something that we should eventually do. I just haven't seen a design I really like.