re initializers
Nah The advice is necessary
because of compiler insertion of a default ctor (parameterless initializer that does nothing)
(On rereading what I wrote probably should have emphasised that that is to provide a (explicit) no-arg ctor rather than allowing a default ctor )
For an immutable object you'd be defining a ctor anyway so its not directly applicable
but its not an 'instant failure' on immutable class objects cos a no-arg ctor can be made to define a
null/zeroed immutable object or a default one ( like the origin point for an immutable point class) and its
existence continues to allow stable subclassing ( with a default (compiler inserted) constructor on the subclass)
worst case without it is is a compiler error for a missing no-arg ctor like youd called a non existent baseclass ctor anyway
for the 'coding an initialiser with initial data' - same thing - allows null/empty object or a convenience default - theres still the basic requirement that a visible object is always in a stable state
Its the same 'instant failure' if the initializer is explicit and calls a baseclass initializer with a signature that doesnt exist - so?
Anyway I've already said I dont disagree(strongly) with the idea of covering all the baseclass initializers though if having coverage of a single no-arg initializer may be confusing to some I'm not sure that covering all baseclass initializers will be less confusing.
re: explicit .init or base.init
I dont have any data on the reality of 'skip the issue' assertion in a) beyond that the ref .init vs ref.base.init and post adjust is probably more a style issue than an instruction.
I'd imagine that the path of least resistance to making the baseclass call explicit would be that the default coding response would be to just boilerplate a call to the base class shadow and then maybe
adjust to what may be a 'better' call
re (c) the resulting problem is not exposed in those languages - the additional needless boilerplate
If we take the cobra source as representative ( debateable but) simple grepping (./Source) gives
about 278 classes ( '^class')
324 lines of cue init ('cue init') => say 46 classes with multiple initializers (~ 17%)
26 lines of no-arg ctor ( 'cue init$') (9.35%) => 90% have arged ctor
53 calls to no-arg base.init ('base.init$') (19 %)
The last line is the overhead.
I'd argue that calls to baseclass arged ctors would need to be done explicitly anyway given that they're not no-arged (:-) and most of the app classes have some sort of arged ctors so forcing all the baseclass calls to be explicit forces a pretty high overhead for the simplest/default case....
I'd imagine (untested assertion) that on a less complex app than the compiler therd be a simpler class/ctor chain of construction and the proportion of ( what should be implicit) refs to base
no-arg ctors would be higher..
Hmmm
Also it seems to me that if its reasonable to shadow all the baseclass initializers as defaults ( cobra virtualized) in cobra subclasses it would also be reasonable to by default implicitly call the sig matching the baseclass initializer if a initializer is explicitly declared
- Code: Select all
class Foo
cue init
pass
cue init(a as int)
pass
cue init(a as int, b as bool)
pass
class Bar inherits Foo
cue init
pass # implicit base.init
cue init(a as int)
pass # implicit base.init(a)
cue init( a as int, b as bool)
pass # implicit base.init(a,b)
cue init(a as int, b as int)
pass # gen warning no explicit call to .init base.init as no matching base.init signature
cue init(b as bool, a as int)
.init(a,b) # explicit always OK