Bug 9066 – Add constructor inheritance feature

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-11-23T11:02:26Z
Last change time
2024-12-13T18:03:00Z
Assigned to
No Owner
Creator
Andrej Mitrovic
Moved to GitHub: dmd#18497 →

Attachments

IDFilenameSummaryContent-TypeSize
1165forward_ctors.dcodeapplication/octet-stream1755

Comments

Comment #0 by andrej.mitrovich — 2012-11-23T11:02:26Z
This would alleviate the need to write boilerplate code by hand, e.g.: class MyException : Exception { mixin ForwardCtors; } An experimental implementation is provided in the attachment.
Comment #1 by andrej.mitrovich — 2012-11-23T11:02:46Z
Created attachment 1165 code
Comment #2 by peter.alexander.au — 2012-12-31T09:57:25Z
*** Issue 8965 has been marked as a duplicate of this issue. ***
Comment #3 by andrej.mitrovich — 2013-02-04T12:00:13Z
There's a few problems: Default values aren't handled, and they could be initialized with a non-accessible private value. The parameter types could also be private types which might not be accessible. It would definitely be simpler to implement inheriting constructors, C++11 has them, described here: http://stackoverflow.com/questions/9979194/what-is-constructor-inheritance Perhaps we could implement something similar via: class C : B { alias super.this this; }
Comment #4 by code — 2013-10-03T15:56:49Z
I think what we want is implicit constructor inheritance even for non-default constructors. The same rules should apply. > Default values aren't handled, and they could be initialized with a non-accessible private value. Depends on the scope of default values, I'm not sure about this right now. If they live in the callee scope it'll work fine. If they live in the caller scope your constructor isn't callable from outside of the module and your constructor should be private. > The parameter types could also be private types which might not be accessible. Same here your constructor should be private. Old forum post on the topic of constructor inheritance. http://forum.dlang.org/thread/[email protected]
Comment #5 by andrej.mitrovich — 2013-10-04T04:09:58Z
Copying my comment from github: C++11 has this feature: http://stackoverflow.com/questions/9979194/what-is-constructor-inheritance I think the only real issue is what syntax to use in D. C++ uses: ----- using Base::Base; ----- At first glance in D it would be: ----- alias Base.this this; // or Super.this ----- But this conflicts with the subtyping syntax.
Comment #6 by code — 2013-10-04T11:27:29Z
(In reply to comment #5) Inheriting the default constructor is implicit so why would you need an explicit syntax for non-default constructors?
Comment #7 by andrej.mitrovich — 2013-10-04T11:37:43Z
(In reply to comment #6) > (In reply to comment #5) > > Inheriting the default constructor is implicit so why would you need an > explicit syntax for non-default constructors? The last time this was discussed (IIRC), people were against this. Maybe my memory is bad. We could have another go at a newsgroup discussion. I haven't yet looked at the C++11 spec, but I wonder why they too haven't made constructor inheritance implicit.
Comment #8 by andrej.mitrovich — 2013-10-04T12:01:23Z
(In reply to comment #6) > (In reply to comment #5) > > Inheriting the default constructor is implicit so why would you need an > explicit syntax for non-default constructors? I guess the real issue is that you could easily end up instantiating an object which hasn't been properly initialized (properly meaning how the class designer defines it). For example: ----- class A { this(float x) { this.x = x; } float x; } class B : A { this(float x, float y) { super(x); this.y = y; } float y; } void main() { auto b = new B(1.0); // B's ctor not called } ----- Nevermind that we have .init, a class designer probably wants to have explicit control of which constructors can be called by the user. If all base class ctors are inherited.. well you saw the example. Another interesting example: ----- class A { this(float x) { this.x = x; } float x; } class B : A { this(float x, float y) { super(x); this.y = y; } const(float) y; } void main() { // this should not compile since y must be initialized // in the class B ctor, which wasn't called. auto b = new B(1.0); } ----- So the user could easily get a half-constructed object, or bad diagnostics about some const field not being initialized.
Comment #9 by code — 2013-10-05T09:01:17Z
(In reply to comment #8) Your example wouldn't compile. You can't default construct a class that defines a non-default constructor even though we do have implicit constructor inheritance. The rule here is very simple, if you define a constructor none is inherited.
Comment #10 by andrej.mitrovich — 2013-10-05T09:59:19Z
(In reply to comment #9) > (In reply to comment #8) > > Your example wouldn't compile. > You can't default construct a class that defines a non-default constructor even > though we do have implicit constructor inheritance. I'm not default-constructing a class in that example. > The rule here is very simple, if you define a constructor none is inherited. I see what you mean, that could work. Although I still want the ability to explicitly re-introduce base-class constructors via some syntax. So in essence we'll have: ----- class A { this(int); this(double); } class B : A { } // implicitly inherits ctors (very useful for Exception) ----- ----- class A { this(int); this(double); } class B : A { this(string); } // does *not* inherit ctors ----- I also want: ----- class A { this(int); this(double); } // inherit the this(int) ctor class B : A { this(string); alias super.this(int) this; } ----- However these two features can be implemented separately, so maybe we should split this up into two enhancement requests.
Comment #11 by code — 2013-10-05T11:49:56Z
(In reply to comment #10) > class A { this(int); this(double); } > > // inherit the this(int) ctor > class B : A { this(string); alias super.this(int) this; } > ----- This is more specific because you have to specify which constructor to inherit by stating the parameter types. So you will save less typing over this(int a) { super(a); }. It's still useful because you can reuse the default arguments and the compiler will check for you that the parameter types match the base class. No good idea for the syntax though. Maybe we can special case the alias syntax as you used it in the example. > so maybe we should split this up into two enhancement requests Makes sense.
Comment #12 by andrej.mitrovich — 2013-10-05T12:10:51Z
(In reply to comment #11) > This is more specific because you have to specify which constructor to inherit > by stating the parameter types. So you will save less typing over this(int a) { > super(a); }. I'm thinking it would save the binary size though (save on duplicated functions that do nothing but forward arguments). Especially if you use a mixin template to autogenerate these (for whatever reason).
Comment #13 by code — 2013-10-11T09:59:26Z
(In reply to comment #10) > I see what you mean, that could work. Although I still want the ability to > explicitly re-introduce base-class constructors via some syntax. So in essence > we'll have: I had an idea how to achieve more flexibility with only a single special case for alias this. - We add implicit constructor inheritance. - When you define a constructor implicit inheritance is disabled. - We special case alias super.this this for explicit inheritance, it is invalid currently and has no useful semantic meaning. It's semantic meaning is overload the super class constructors with the local constructors. - You can use @disable this(int) in the derived class to selectively disable some of the super class constructors.
Comment #14 by andrej.mitrovich — 2013-10-11T11:21:54Z
(In reply to comment #13) > I had an idea how to achieve more flexibility with only a single > special case for alias this. Sounds good to me. Kenji what are your thoughts?
Comment #15 by code — 2014-10-20T09:55:55Z
This has been requested before by Sean Kelly with a good description. http://forum.dlang.org/thread/[email protected]
Comment #16 by code — 2014-10-20T09:56:16Z
We should probably write a DIP for it.
Comment #17 by andrej.mitrovich — 2016-09-04T11:27:25Z
(In reply to Martin Nowak from comment #13) > - You can use @disable this(int) in the derived class to selectively > disable some of the super class constructors. Thinking about this now, I think this specific point may be a bad idea since the base class may be in a 3rd part library. If the authors of the base class introduce yet another new constructor you have to be vigilant and check if you need to add any new @disable this(...) declarations in your own subclass. This is similar to the base class method hijacking problem https://dlang.org/hijack.html ("Base Class Member Function Hijacking"), but it would be a bigger problem for constructors as listed in https://issues.dlang.org/show_bug.cgi?id=9066#c8 I'll begin working on a DIP.
Comment #18 by andrej.mitrovich — 2016-09-04T14:03:25Z
Comment #19 by andrej.mitrovich — 2016-09-04T14:04:24Z
(In reply to Andrej Mitrovic from comment #18) > https://github.com/dlang/DIPs/pull/42 And yes I omitted the whole `super(Arguments)` stuff as I believe it would complicate the implementation. C++11 doesn't seem to add support for inheriting specific constructors, and it seems that wasn't a cause for concern.
Comment #20 by robert.schadek — 2024-12-13T18:03:00Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18497 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB