Interesting Research Paper on Constructors in OO Languages
Regan Heath
regan at netmail.co.nz
Wed Jul 17 03:00:38 PDT 2013
On Tue, 16 Jul 2013 23:01:57 +0100, H. S. Teoh <hsteoh at quickfur.ath.cx>
wrote:
> On Tue, Jul 16, 2013 at 06:17:48PM +0100, Regan Heath wrote:
>> On Tue, 16 Jul 2013 14:34:59 +0100, Craig Dillabaugh
>> <cdillaba at cg.scs.careton.ca> wrote:
>>
>> >On Tuesday, 16 July 2013 at 09:47:35 UTC, Regan Heath wrote:
>> >
>> >clip
>> >
>> >>
>> >>We have class invariants.. these define the things which must be
>> >>initialised to reach a valid state. If we had compiler
>> >>recognisable properties as well, then we could have an
>> >>initialise construct like..
>> >>
>> >>class Foo
>> >>{
>> >> string name;
>> >> int age;
>> >>
>> >> invariant
>> >> {
>> >> assert(name != null);
>> >> assert(age > 0);
>> >> }
>> >>
>> >> property string Name...
>> >> property int Age...
>> >>}
>> >>
>> >>void main()
>> >>{
>> >> Foo f = new Foo() {
>> >> Name = "test", // calls property Name setter
>> >> Age = 12 // calls property Age setter
>> >> };
>> >>}
>
> Maybe I'm missing something obvious, but isn't this essentially the same
> thing as having named ctor parameters?
Yes, if we're comparing this to ctors with named parameters. I wasn't
doing that however, I was asking this Q:
"Or, perhaps another way to ask a similar W is.. can the compiler
statically verify that a create-set-call style object has been
initialised, or rather that an attempt has at least been made to
initialise all the required parts."
Emphasis on "create-set-call" :) The weakness to create-set-call style is
the desire for a valid object as soon as an attempt can be made to use
it. Which implies the need for some sort of enforcement of initialisation
and as I mentioned in my first post the issue of preventing this
intialisation being spread out, or intermingled with others and thus
making the semantics of it harder to see.
My idea here attempted to solve those issues with create-set-call only.
> [...]
>> The idea was to /use/ the code in the invariant to determine which
>> member fields should be set during the initialisation statement and
>> then statically verify that a call was made to some member function
>> to set them. The actual values set aren't important, just that some
>> attempt has been made to set them. That's about the limit of what I
>> think you could do statically, in the general case.
> [...]
>
> This still doesn't address the issue of ctor argument proliferation,
> though
It wasn't supposed to :) create-set-call ctors have no arguments.
> if each level of the class hierarchy adds 1-2 additional
> parameters, you still need to write tons of boilerplate in your derived
> classes to percolate those additional parameters up the inheritance
> tree.
In the create-set-call style additional required 'arguments' would appear
as setter member functions whose underlying data member is verified in the
invariant and would therefore be enforced by the syntax I detailed.
> Now imagine if at some point you need to change some base class ctor
> parameters. Now instead of making a single change to the base class, you
> have to update every single derived class to make the same change to
> every ctor, so that the new version of the parameter (or new parameter)
> is properly percolated up the inheritance tree.
This is one reason why create-set-call might be desirable, no ctor
arguments, no problem.
So, to take my idea a little further - WRT class inheritance. The
compiler, for a derived class, would need to inspect the invariants of all
classes involved (these are and-ed already), inspect the constructors of
the derived classes (for calls to initialise members), and the
initialisation block I described and verify statically that an attempt was
made to initialise all the members which appear in all the invariants.
> I think my approach of using builder structs with a parallel inheritance
> tree is still better
It may be, it certainly looked quite neat but I haven't had a detailed
look at it TBH. I think you've missunderstood my idea however, or rather,
the issues it was intended to solve :) Perhaps my idea is too limiting
for you? I could certainly understand that point of view.
I think another interesting idea is using the builder pattern with
create-set-call objects.
For example, a builder template class could inspect the object for UDA's
indicating a data member which is required during initialisation. It
would contain a bool[] to flag each member as not/initialised and expose a
setMember() method which would call the underlying object setMember() and
return a reference to itself.
At some point, these setMember() method would want to return another
template class which contained just a build() member. I'm not sure how/if
this is possible in D.
R
--
Using Opera's revolutionary email client: http://www.opera.com/mail/
More information about the Digitalmars-d
mailing list