www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - struct constructors and function parameters

reply Adam Burton <adz21c gmail.com> writes:
Hi,
should the below work? 

struct A
{
    public this(B b) {}
}

struct B {}

void foo(A a) {}

void main()
{
    B b;
    foo(b);     // Fails
}

The constructor parameter doesn't need to be a struct, it could be an int. 
The workaround is to explicity call the constructor.
Nov 09 2010
next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Adam Burton <adz21c gmail.com> wrote:

 Hi,
 should the below work?

 struct A
 {
     public this(B b) {}
 }

 struct B {}

 void foo(A a) {}

 void main()
 {
     B b;
     foo(b);     // Fails
 }

 The constructor parameter doesn't need to be a struct, it could be an  
 int.
 The workaround is to explicity call the constructor.
Far as I know, that's not supposed to work, no. Guess it has to do with overloading: struct foo { this( int n ){} } void bar( foo f ) {} void bar( int n ) {} bar( 3 ); // which do I call? -- Simen
Nov 09 2010
next sibling parent reply Adam Burton <adz21c gmail.com> writes:
Simen kjaeraas wrote:

 Adam Burton <adz21c gmail.com> wrote:
 
 Hi,
 should the below work?

 struct A
 {
     public this(B b) {}
 }

 struct B {}

 void foo(A a) {}

 void main()
 {
     B b;
     foo(b);     // Fails
 }

 The constructor parameter doesn't need to be a struct, it could be an
 int.
 The workaround is to explicity call the constructor.
Far as I know, that's not supposed to work, no. Guess it has to do with overloading: struct foo { this( int n ){} } void bar( foo f ) {} void bar( int n ) {} bar( 3 ); // which do I call?
True, I had thought of that, but I figured in that situation it would favour int over foo (in same way long vs int) so to access foo you'd need to explicitly use the constructor. On the other hand I suppose its more of a difficult decision when you hit something like below struct A { this(int) } struct B { this(int) } void bar(A) void bar(B) Again though you could argue to explicitly specify the constructor of the appropriate struct.
Nov 09 2010
parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Adam Burton <adz21c gmail.com> wrote:

 True, I had thought of that, but I figured in that situation it would  
 favour
 int over foo (in same way long vs int) so to access foo you'd need to
 explicitly use the constructor. On the other hand I suppose its more of a
 difficult decision when you hit something like below

 struct A
 {
    this(int)
 }
 struct B
 {
    this(int)
 }

 void bar(A)
 void bar(B)
Yup. That was what I'd planned to write, but then my brain took a shortcut. :p As you say though, overloading rules mean the int version would be chosen. -- Simen
Nov 09 2010
prev sibling parent div0 <div0 sourceforge.net> writes:
On 09/11/2010 23:57, Simen kjaeraas wrote:
 Adam Burton <adz21c gmail.com> wrote:

 Hi,
 should the below work?

 struct A
 {
 public this(B b) {}
 }

 struct B {}

 void foo(A a) {}

 void main()
 {
 B b;
 foo(b); // Fails
 }

 The constructor parameter doesn't need to be a struct, it could be an
 int.
 The workaround is to explicity call the constructor.
Far as I know, that's not supposed to work, no. Guess it has to do with overloading: struct foo { this( int n ){} } void bar( foo f ) {} void bar( int n ) {} bar( 3 ); // which do I call?
This does work in C++. As for D, dunno. There are arguments both ways and this is why C++ has the 'explicit' keyword. The 'explicit' keyword specifically stops the example compiling. So they kinda work the same way but from opposite ends. For me, I prefer the D way; in my code at work the 'explicit' keyword seems to confuse a lot of people. -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk
Nov 09 2010
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, November 09, 2010 15:48:27 Adam Burton wrote:
 Hi,
 should the below work?
 
 struct A
 {
     public this(B b) {}
 }
 
 struct B {}
 
 void foo(A a) {}
 
 void main()
 {
     B b;
     foo(b);     // Fails
 }
 
 The constructor parameter doesn't need to be a struct, it could be an int.
 The workaround is to explicity call the constructor.
It should _not_ work. D does not support implicit conversions like that. You might be able to get it work with alias this, but that would be very different from expecting the compiler to cast a B to an A using A's constructor in order to call a function. C++ does that sort of thing all the time, but it can make it very hard to figure out which function overload is actually being called and why. It can be quite error prone. So, D is much pickier. You should look at http://www.digitalmars.com/d/2.0/function.html - particularly the section on overloading. Generally, types must match exactly when calling a function. There is some leeway with some of the primitive types and if there is no ambiguity class objects can be implicitly cast to a base class in a function call, but there certainly isn't anything for structs, since they don't have inheritance. - Jonathan M Davis
Nov 09 2010
parent reply Adam Burton <adz21c gmail.com> writes:
Jonathan M Davis wrote:

 On Tuesday, November 09, 2010 15:48:27 Adam Burton wrote:
 Hi,
 should the below work?
 
 struct A
 {
     public this(B b) {}
 }
 
 struct B {}
 
 void foo(A a) {}
 
 void main()
 {
     B b;
     foo(b);     // Fails
 }
 
 The constructor parameter doesn't need to be a struct, it could be an
 int. The workaround is to explicity call the constructor.
It should _not_ work. D does not support implicit conversions like that. You might be able to get it work with alias this, but that would be very different from expecting the compiler to cast a B to an A using A's constructor in order to call a function. C++ does that sort of thing all the time, but it can make it very hard to figure out which function overload is actually being called and why. It can be quite error prone. So, D is much pickier. You should look at http://www.digitalmars.com/d/2.0/function.html - particularly the section on overloading. Generally, types must match exactly when calling a function. There is some leeway with some of the primitive types and if there is no ambiguity class objects can be implicitly cast to a base class in a function call, but there certainly isn't anything for structs, since they don't have inheritance. - Jonathan M Davis
I figured that was the case I just wanted to confirm :-) I looked into alias this and it does indeed work, unless the alias is to a function. That has been reported as a bug though http://d.puremagic.com/issues/show_bug.cgi?id=2814
Nov 09 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Adam Burton <adz21c gmail.com> wrote:

 I looked into alias this and it does indeed work, unless the alias is to  
 a
 function. That has been reported as a bug though
 http://d.puremagic.com/issues/show_bug.cgi?id=2814
Wouldn't that be the opposite of what you were discussing earlier? alias this lets a struct behave as an or whatever, not the other way around. -- Simen
Nov 09 2010
parent Adam Burton <adz21c gmail.com> writes:
Simen kjaeraas wrote:

 Adam Burton <adz21c gmail.com> wrote:
 
 I looked into alias this and it does indeed work, unless the alias is to
 a
 function. That has been reported as a bug though
 http://d.puremagic.com/issues/show_bug.cgi?id=2814
Wouldn't that be the opposite of what you were discussing earlier? alias this lets a struct behave as an or whatever, not the other way around.
You've lost me. I think you are getting at the fact that alias this isn't exactly the same as structs using constructors for implicit casts. I was just acknowledging I have looked into it (I am using it for something else but that bug gets in my way :-(). That being said if you make the alias this a factory method for your implicit casts it could be used to do so. For example struct D { int i; alias implicitCast this; E implicitCast() { return E(i); } } struct E { int i; } void main() { E e = E(1); D d = D(2); e = d; writefln(to!string(e.i)); // 2 } As stated by the bug this doesn't work for function parameters. With member variables it is ok though. Mentioning our earlier discussion I don't see why the implicit casts couldn't be handled in the same manner as below. interface A {} interface B {} class C : B, A {} void foo(A a){} void foo(B b){} void main() { foo(new C()); } test2.d(15): Error: function test2.foo called with argument types: ((C)) matches both: test2.foo(A a) and: test2.foo(B b)
Nov 10 2010