Bug 3680 – default struct constructor should not be removed
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-01-06T07:37:57Z
Last change time
2018-05-28T10:07:53Z
Assigned to
No Owner
Creator
ibrahim YANIKLAR
Comments
Comment #0 by yanikibo — 2010-01-06T07:37:57Z
1) I think the default struct constructor should not be removed when another constructor is implemented so that overriding the default constructor is not allowed.
struct S {
this(int a) { }
}
S* s = new S(0); // OK
S* s = new S(); // should be allowed
2) the default constructor can be overriden like below.
I think it shold not be allowed.
struct S {
this(int a = 0) {}
}
Comment #1 by michel.nolard — 2010-01-11T04:20:17Z
Can you provide arguments to help determining weither the current situation or your proposal is a better way.
> 1) I think the default struct constructor should not be removed when another
> constructor is implemented so that overriding the default constructor is not
> allowed.
>
> struct S {
> this(int a) { }
> }
>
> S* s = new S(0); // OK
> S* s = new S(); // should be allowed
>
>
> 2) the default constructor can be overriden like below.
> I think it shold not be allowed.
>
> struct S {
> this(int a = 0) {}
> }
Comment #2 by yanikibo — 2010-01-12T07:11:33Z
The practical reason:
---------------------
Sometimes you need to use the default constructor near your non-default constructors. And there is not any way to do that, expect "this(int a = 0) { }".
More clearly: implementing a non-default constructor does not always mean that you don't need the default constructor. In classes, If you need it simply you can add it, but in structs you can not.
Sometimes you don't know the type and you need to create an instance (like "new T").
Since it is a value type, you can initialize it by some different ways, therefore it is meaningless to remove the default constructor.
Some ways to initialize:
S* s1 = cast(S*)new void[S.sizeof];
S* s2 = cast(void*)GC.malloc(S.sizeof);
*s2 = S.init
This is better I think:
S* s1 = new S;
I will explain some logical reasons but my poor english slowes me down very much.
> Can you provide arguments to help determining weither the current situation or
> your proposal is a better way.
>
> > 1) I think the default struct constructor should not be removed when another
> > constructor is implemented so that overriding the default constructor is not
> > allowed.
> >
> > struct S {
> > this(int a) { }
> > }
> >
> > S* s = new S(0); // OK
> > S* s = new S(); // should be allowed
> >
> >
> > 2) the default constructor can be overriden like below.
> > I think it shold not be allowed.
> >
> > struct S {
> > this(int a = 0) {}
> > }
Comment #3 by yanikibo — 2010-01-12T07:31:11Z
The logical reason:
-------------------
There are two methods of using the value types.
One is using them directly. and the other is to use them with pointers arithmetic.
I think the two methods should be parallel about defaults, restrictions, etc.
And all the value types must have common rules.
Examples:
int i1; // i1 == int.init;
int* i2 = new int; // *i2 == int.init
the compiler allowes that:
int* i3 = new int(); // *i3 == int.init
therefore, in parallel it would be nice to allow that:
int i4 = int(); // i4 == int.init
or two of them can be removed;
for structs:
struct S {
.... // constructors are defined or not
}
S s1;
S* s2 = new S;
Since it is a rule that s1 == S.init, I think the value of *s2 should be S.init too regardless of implementing any constructor or not.
The restrictions and defaults on "this()" and "static ... opCall()" should be parallel.
If "static ... opCall()" can be implemented, "this()" should be able to be implemented,
else they should never be removed and should always act like S.init (I think this is the best).
S s3 = S(); // s1 == S.init
S* s4 = new S(); // *s4 == S.init
To remove static opCall's completely is another subject...
(In reply to comment #2)
> The practical reason:
> ---------------------
> Sometimes you need to use the default constructor near your non-default
> constructors. And there is not any way to do that, expect "this(int a = 0) {
> }".
> More clearly: implementing a non-default constructor does not always mean that
> you don't need the default constructor. In classes, If you need it simply you
> can add it, but in structs you can not.
> Sometimes you don't know the type and you need to create an instance (like "new
> T").
> Since it is a value type, you can initialize it by some different ways,
> therefore it is meaningless to remove the default constructor.
>
> Some ways to initialize:
>
> S* s1 = cast(S*)new void[S.sizeof];
>
> S* s2 = cast(void*)GC.malloc(S.sizeof);
> *s2 = S.init
>
> This is better I think:
> S* s1 = new S;
>
> I will explain some logical reasons but my poor english slowes me down very
> much.
>
>
> > Can you provide arguments to help determining weither the current situation or
> > your proposal is a better way.
> >
> > > 1) I think the default struct constructor should not be removed when another
> > > constructor is implemented so that overriding the default constructor is not
> > > allowed.
> > >
> > > struct S {
> > > this(int a) { }
> > > }
> > >
> > > S* s = new S(0); // OK
> > > S* s = new S(); // should be allowed
> > >
> > >
> > > 2) the default constructor can be overriden like below.
> > > I think it shold not be allowed.
> > >
> > > struct S {
> > > this(int a = 0) {}
> > > }
Comment #4 by michel.nolard — 2010-01-15T03:13:06Z
Ok. I clearly see your point now, and it is both practical and logical ... and I agree ! This would be quite an improvement for a lot of situations.
What bothers me is this :
> To remove static opCall's completely is another subject...
In fact, your proposal - which is a good one - implies from "the opCall and default constructor removal" problem to be solved at the same time.
Imagine someone relying upon the constructor removal "feature" you depict and who would not be able to make things work in a new version. This can not be admitted. Both problems must definitely be solved and their solution's integration be planned for the same release.
A case which needs clarification, by the way, is when the struct is externalized to C which does not prohibits the default construction to be used...
Comment #5 by yanikibo — 2010-01-15T08:43:21Z
> What bothers me is this :
> > To remove static opCall's completely is another subject...
I will explain that by opening a new issue.
> A case which needs clarification, by the way, is when the struct is
> externalized to C which does not prohibits the default construction to be
> used...
The implementation of the default constructor should be prohibited as the current situation. Also the implementation of the default opCall (static ... opCall()) should be prohibited. And implementing a non-default constructor or a non default opCall should not cause the removal of the defaults.
------------------------------
struct S {
...
this() { ... } // should give error
}
------------------------------
struct S {
...
static S opCall() { ... } // should give error
}
------------------------------
struct S {
...
this(int a) { ... }
static S opcall(double d) { ... }
}
S s = S(); // should work
S* s = new S(); // should work
------------------------------
Is this proposal causes a problem like you have depicted? Probably I could not understand your case.
Comment #6 by yanikibo — 2010-01-15T09:57:39Z
Also "this(int a = 0)" and "static ... opCall(int a = 0)" should be prohibited.
Comment #7 by clugdbug — 2010-01-15T11:45:32Z
(In reply to comment #6)
> Also "this(int a = 0)" and "static ... opCall(int a = 0)" should be prohibited.
That's bug 3438. I think the underlying issue is, that we need this() with no parameters.
Comment #8 by michel.nolard — 2010-01-19T02:50:53Z
* This comment is more a remainder for myself than a new comment. *
There is a way to introduce a opAssign( typeof( this ) rhs ) using templates, although it is prohibited. The technique can be _accidentally_ (I ensure you this really happens) used to add a opCall or this with the wrong signature. This is based on the fact that the template's type inference occurs at a different time than the opAssign's signature validation.
I just have to find back where I used it to give you an example to be sure that that case also is managed in the proposal.
Comment #9 by razvan.nitu1305 — 2018-05-28T10:07:53Z
This has been fixed. Both lines in test case 1) compile now and for test case 2) a deprecation is issued. I am referring to the test cases in the original bug report. Closing as fixed.