www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - constructor instead of opCall for an instance of a template alias

reply "comco" <void.unsigned gmail.com> writes:
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
parent reply "Rob T" <rob ucora.com> writes:
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
parent reply "comco" <void.unsigned gmail.com> writes:
 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
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/25/2012 07:27 AM, comco wrote:
 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,
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 // ... }
 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
parent "comco" <void.unsigned gmail.com> writes:
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/

 Ali
Filed an issue 9078.
Nov 25 2012
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 25 November 2012 at 15:27:53 UTC, comco wrote:
 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:
Welcome to D structs creation puzzle.
 skipped
If 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
parent "Rob T" <rob ucora.com> writes:
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