Comment #0 by Jesse.K.Phillips+D — 2014-02-18T11:02:49Z
In 2.064 the following code worked as expected, with 2.065rc1 this fails to compile with a hidden static opCall message. Structs can't have a default constructor; is this approach deprecated in favor of the factory method?
I'd like to note that by removing the static opCall, the compilation succeeds but runtime will fail; this of course means tracking down the places which need fixed is not helped by the compiler.
void main() {
assert(Struct() == Struct(2));
}
struct Struct {
int a;
this(int a) {
this.a = a;
}
static Struct opCall() {
return Struct(2);
}
}
--------
test.d(10): Error: struct test.Struct static opCall is hidden by constructors and can never be called
test.d(10): Please use a factory method instead, or replace all constructors with static opCall.
Comment #1 by andrej.mitrovich — 2014-02-18T12:36:05Z
I knew this was going to be a problem as soon I saw the pull implementing the change. But some pople insist on destroying any means of defining a default ctor even though everybody else demands it.
Comment #2 by andrej.mitrovich — 2014-02-18T12:36:24Z
(In reply to comment #1)
> I knew this was going to be a problem as soon I saw the pull implementing the
> change. But some pople insist on destroying any means of defining a default
> ctor even though everybody else demands it.
s/pople/people :)
Comment #3 by dmitry.olsh — 2014-02-18T12:53:54Z
In this light I long ago gave up on _public_ constructors and use factory function everywhere for consistency. This way I finally get:
- 0 argument construction
- IFTI in case of templates
- UFCS notation such as 1.inch
Sadly it's solely convention based.
Comment #4 by samukha — 2014-02-18T13:44:12Z
(In reply to comment #1)
> I knew this was going to be a problem as soon I saw the pull implementing the
> change. But some pople insist on destroying any means of defining a default
> ctor even though everybody else demands it.
Black out default constructors just to make people fake those with factory functions. I think that's ok, pretty much in line with modern trends in software development.
Comment #5 by Jesse.K.Phillips+D — 2014-02-18T14:04:47Z
I'm not really against the change, but I do think it is dangerous since the compiler can't/doesn't verify the needed changes were made.
Comment #6 by bugzilla — 2014-02-18T17:51:11Z
(In reply to comment #5)
> I'm not really against the change, but I do think it is dangerous since the
> compiler can't/doesn't verify the needed changes were made.
In this case, the compiler does give a message.
Mixing constructors and static opCall makes a struct hard to reason about and also resulted in some arbitrary behavior by the compiler. I.e. this change came about because of fixing other bugzilla issues.
I'm going to mark it as wontfix because it is an intended change.
I apologize for the breaking of the existing code, and for not handling this behavior change better.
Comment #7 by k.hara.pg — 2014-02-18T18:38:54Z
This change has been introduced to fix the language design issue discovered by bug 12070 (the diagnostic message is added by issue 12124).
In D1 age, historically static opCall was a hack to use C++ like syntax for object construction.
In D2, It has not been recommended because constructor is properly supported for structs.
Until 2.064, constructor takes precedence over static opCall _in most cases_.
For example, if you mix constructors and static opCall that take arguments, static opCall is always hidden.
struct S {
this(int n) {}
static void opCall(int n, int m) {}
}
void main() {
auto s = S(1); // call this(int)
auto s = S(1, 2); // error, this(int) is not callable using two int arguments
}
But if static opCall has no arguments, it had been allowed for S(), like as OP-code.
----
However, the language behavior will cause a problem if opCall method is not static. Following is the sample code that summarize bug 12070.
struct S {
this(int n) {}
void opCall() {}
}
void main() {
auto s = S(); // need 'this' for S.opCall()
}
Note the behavior that S.opCall() will match to the instance opCall.
D does not have the feature to resolve function overloading based on the 'static' attribute, as same as C++.
Although it is definitely legitimate to define both regular constructors and non-static opCall, the code had not work contrary to the expectation until 2.064.
From 2.065, in order to fix the design issue, the syntax `Type()` is always reserved for default construction if one or more user defined constructors exist.
And it will conform to the D2 intention that using static opCall for construction has not been recommended.
Comment #8 by k.hara.pg — 2014-02-18T18:41:25Z
(In reply to comment #0)
> this of course means tracking down the places which need
> fixed is not helped by the compiler.
> this of course means tracking down the places which need
fixed is not helped by the compiler.
You can make error at the all places that using `static Struct opCall()`, by replacing it to `@disable this();`.
> void main() {
> assert(Struct() == Struct(2));
> }
>
> struct Struct {
> int a;
> this(int a) {
> this.a = a;
> }
@disable this();
//static Struct opCall() {
// return Struct(2);
//}
> }
--------
test.d(2): Error: constructor test.Struct.this is not callable because it is annotated with @disable
Comment #9 by Jesse.K.Phillips+D — 2014-02-18T20:02:35Z
(In reply to comment #8)
> You can make error at the all places that using `static Struct opCall()`, by
> replacing it to `@disable this();`.
Perfect recommendation, thank you.