digitalmars.D.learn - constructor instead of opCall for an instance of a template alias
- comco (28/28) Nov 24 2012 I have the following snippet:
- Rob T (10/38) Nov 24 2012 struct A(alias Method) is a template taking in some to be defined
- comco (38/40) Nov 25 2012 Why is that? Here method is an instance of the type Method, not
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (32/39) Nov 25 2012 That could be case but you original code did use a type name for Method:
- comco (2/5) Nov 25 2012 Filed an issue 9078.
- Maxim Fomin (23/30) Nov 25 2012 If you change return type from void to e.x. int, dmd will still
- Rob T (8/14) Nov 25 2012 Looks like something was fixed with 2.061, the sample code now
I have the following snippet: struct A(alias Method) { string s; this(Method method) { method(s); // 5 } } struct B { this(int i) { } void opCall(string s) { } } void main() { A!B(B(0)); } This code fails to compile with the following errors: test.d(5): Error: constructor test.B.this (int i) is not callable using argument types (string) test.d(5): Error: cannot implicitly convert expression (this.s) of type string to int test.d(17): Error: template instance test.A!(B) error instantiating shell returned 1 It looks like the compiler is confusing the `method` instance parameter with the `Method` class. If I replace line 5 with `method.opCall(s);` it compiles. Can you explain this behaviour please?
Nov 24 2012
On Saturday, 24 November 2012 at 20:34:39 UTC, comco wrote:I have the following snippet: struct A(alias Method) { string s; this(Method method) { method(s); // 5 } } struct B { this(int i) { } void opCall(string s) { } } void main() { A!B(B(0)); } This code fails to compile with the following errors: test.d(5): Error: constructor test.B.this (int i) is not callable using argument types (string) test.d(5): Error: cannot implicitly convert expression (this.s) of type string to int test.d(17): Error: template instance test.A!(B) error instantiating shell returned 1 It looks like the compiler is confusing the `method` instance parameter with the `Method` class. If I replace line 5 with `method.opCall(s);` it compiles. Can you explain this behaviour please?struct A(alias Method) is a template taking in some to be defined type named Method. I'm not sure why "alias" is there, you can remove it. A!B(...) defines a struct A with B typed in as Method, so call to method(s); is the same as B(string) but there's no B.this(string) defined for B, causing the compiler to complain. method.opCall(s); is B.opCall(s) which is defined, and that is why it will compile. --rt
Nov 24 2012
A!B(...) defines a struct A with B typed in as Method, so call to method(s); is the same as B(string)Why is that? Here method is an instance of the type Method, not the type Method itself, so by saying `method(s)` we can't mean a constructor. Something very strange happens... I have a simpler example now: import std.stdio; enum ok = true; struct A { int i; static if (ok) { this(int i) { this.i = i; writeln("A.ctor();"); } } void opCall(int i) { writeln("A.opCall()"); } } void main() { static if (ok) { A(0); } else { A(); } } This example works as expected, and it prints: A.ctor(). But if I change it to enum ok = false, then the above code doesn't compile with an Error: function LowestAncestor.A.opCall (int i) is not callable using argument types (). So this might mean that the compiler becomes confused somehow and thinks that we want to call opCall on a static instance (which is not even possible, because opCall is an instance method), and not the default constructor.
Nov 25 2012
On 11/25/2012 07:27 AM, comco wrote:That could be case but you original code did use a type name for Method: A!B(B(0)); This would be using an instance: B instance; A!instance(B(0)); It would not compile because you would be using an instance as a type name in the constructor signature: this(Method method) { // <-- ERROR: Method is an instance // ... }A!B(...) defines a struct A with B typed in as Method, so call to method(s); is the same as B(string)Why is that? Here method is an instance of the type Method, not the type Method itself,so by saying `method(s)` we can't mean a constructor. Something very strange happens...The situation with constructors and opCall() are still confused. There are a number of bugs open but not exactly this one.I have a simpler example now:Even simpler: struct A { int i; void opCall(int i) { } } void main() { auto a = A(42); } Error: variable deneme.main.a type void is inferred from initializer opCall(42), and variables cannot be of type void Error: expression opCall(42) is void and has no value The bug is that a non-static opCall() is chosen instead of the default constructor. As you say, non-static opCall() overloads should not interfere with construction. Could you please create a bug report: http://d.puremagic.com/issues/ Ali
Nov 25 2012
On Sunday, 25 November 2012 at 16:01:39 UTC, Ali Çehreli wrote:Could you please create a bug report: http://d.puremagic.com/issues/ AliFiled an issue 9078.
Nov 25 2012
On Sunday, 25 November 2012 at 15:27:53 UTC, comco wrote:Welcome to D structs creation puzzle.A!B(...) defines a struct A with B typed in as Method, so call to method(s); is the same as B(string)Why is that? Here method is an instance of the type Method, not the type Method itself, so by saying `method(s)` we can't mean a constructor. Something very strange happens... I have a simpler example now:skippedIf you change return type from void to e.x. int, dmd will still complain "Error: need 'this' to access member opCall". There are two problems here: firstly, by some reason dmd does not distinguish between static and non static methods in a sense that it allows to call static method on instance and takes into account non-static methods with expression operating on types (like this case). Secondly, and again by some reason three "semantic things" such as struct literals, struct constructors and opCalls use same syntax like "S()" (let alone it may be non-member function). This makes their priority order an issue - for 2.060 version it is: 1)opCall 2)ctor 3)literal. This is why dmd complains about "A.opCall (int i) is not callable using argument types ()": it recognizes an opCall method, does not take into account staticness and tries to convert A() into opCall invocation. Recently I saw a major pull affecting this behavior, so in 2.061 the situation may be changed (I haven't bother to figure yet). In practice this makes a tricky thing to understand what S() is and creates a problem when you e.x. heavily use struct ctor, write opCall method and everything breaks due to dmd tries now to call opCall instead of ctor.
Nov 25 2012
On Sunday, 25 November 2012 at 16:42:03 UTC, Maxim Fomin wrote:Recently I saw a major pull affecting this behavior, so in 2.061 the situation may be changed (I haven't bother to figure yet). In practice this makes a tricky thing to understand what S() is and creates a problem when you e.x. heavily use struct ctor, write opCall method and everything breaks due to dmd tries now to call opCall instead of ctor.Looks like something was fixed with 2.061, the sample code now refuses to compile, which is correct behavior. void main() { auto a = A(42); } source/main.d(10): Error: need 'this' for opCall type void(int i) --rt
Nov 25 2012