www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - structs inheriting from and implementing interfaces

reply Mike Franklin <slavo5150 yahoo.com> writes:


----
using System;

interface IPrint
{
     void Print();
}

struct MyStruct : IPrint
{
     public void Print()
     {
         Console.WriteLine(ToString());
     }
}

public class Program
{
     public static void Main()
     {
         MyStruct s = new MyStruct();
         s.Print();
     }
}
----
https://dotnetfiddle.net/lpXR1O

But in D it doesn't appear possible.
----
import std.stdio;

interface IPrint
{
     void print();
}

// Error: base classes are not allowed for struct, did you mean ;?
struct MyStruct : IPrint   // Error: base classes are not allowed 
for struct, did you mean ;?
{
     void print()
     {
         writeln("MyStruct");
     }
}

void main()
{
	MyStruct s;
     s.Print();
}
----
https://run.dlang.io/is/j4xwla

Is that simply because it hasn't been implemented or suggested 
yet for D, or was there a deliberate design decision?

Thanks for your insight,

Mike
Dec 29 2017
next sibling parent Seb <seb wilzba.ch> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:


 ----
 using System;

 interface IPrint
 {
     void Print();
 }

 struct MyStruct : IPrint
 {
     public void Print()
     {
         Console.WriteLine(ToString());
     }
 }

 public class Program
 {
     public static void Main()
     {
         MyStruct s = new MyStruct();
         s.Print();
     }
 }
 ----
 https://dotnetfiddle.net/lpXR1O

 But in D it doesn't appear possible.
 ----
 import std.stdio;

 interface IPrint
 {
     void print();
 }

 // Error: base classes are not allowed for struct, did you mean 
 ;?
 struct MyStruct : IPrint   // Error: base classes are not 
 allowed for struct, did you mean ;?
 {
     void print()
     {
         writeln("MyStruct");
     }
 }

 void main()
 {
 	MyStruct s;
     s.Print();
 }
 ----
 https://run.dlang.io/is/j4xwla

 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?

 Thanks for your insight,

 Mike
I think it simply hasn't been implemented, but I am not sure here because you could simply insert a `static assert` in there (and probably have something like `hasInterface!(Interface, YourStruct)`. Similarly multiple `alias this` is a request that often comes up.
Dec 29 2017
prev sibling next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
Structs are structs, classes are classes.

C++ had the mixed model similar to what you suggested, we got it right 
and kept it nice and separate. This was done on purpose.
Dec 29 2017
parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Friday, 29 December 2017 at 12:11:46 UTC, rikki cattermole 
wrote:
 Structs are structs, classes are classes.
I'm talking about interfaces, which are neither structs nor classes.
 C++ had the mixed model similar to what you suggested, we got 
 it right and kept it nice and separate. This was done on 
 purpose.
demonstrates. Mike
Dec 29 2017
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, December 29, 2017 12:18:57 Mike Franklin via Digitalmars-d-learn 
wrote:
 On Friday, 29 December 2017 at 12:11:46 UTC, rikki cattermole

 wrote:
 Structs are structs, classes are classes.
I'm talking about interfaces, which are neither structs nor classes.
Interfaces are related to classes and not structs. Structs do not have inheritance and do not implement interfaces in any way shape or form. Classes and interfaces are always references, whereas structs never are, and structs do not have virtual functions. Structs are either directly placed where they are (be it on the stack or inside an object that contains them), or they're placed on the heap and accessed via a pointer. As such, in D, structs are fundamentally different from classes or interfaces. If you want a function to accept multiple types of structs or classes which share the same API, then use templates and use the template constraint to restrict what the template accepts. That's what's done with ranges (e.g. with isInputRange and isForwardRange). - Jonathan M Davis
Dec 29 2017
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:


 ----
 using System;

 interface IPrint
 {
     void Print();
 }

 struct MyStruct : IPrint
 {
     public void Print()
     {
         Console.WriteLine(ToString());
     }
 }

 public class Program
 {
     public static void Main()
     {
         MyStruct s = new MyStruct();
         s.Print();
     }
 }
 ----
 https://dotnetfiddle.net/lpXR1O

 But in D it doesn't appear possible.
 ----
 import std.stdio;

 interface IPrint
 {
     void print();
 }

 // Error: base classes are not allowed for struct, did you mean 
 ;?
 struct MyStruct : IPrint   // Error: base classes are not 
 allowed for struct, did you mean ;?
 {
     void print()
     {
         writeln("MyStruct");
     }
 }

 void main()
 {
 	MyStruct s;
     s.Print();
 }
 ----
 https://run.dlang.io/is/j4xwla

 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?

 Thanks for your insight,

 Mike
The problem is that interfaces are a runtime thing (e.g. you can cast a class to an interface) structs implement compile time interfaces via template duck typing (usually enforced via an if()). you could probably write a wrapper that introspected an interface and enforced that all members were implemented.
Dec 29 2017
parent reply rjframe <dlang ryanjframe.com> writes:
On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:

 On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:

 The problem is that interfaces are a runtime thing (e.g. you can cast a
 class to an interface)
 structs implement compile time interfaces via template duck typing
 (usually enforced via an if()).
 you could probably write a wrapper that introspected an interface and
 enforced that all members were implemented.
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Dec 29 2017
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 29/12/2017 12:59 PM, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:
 
 On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:

 The problem is that interfaces are a runtime thing (e.g. you can cast a
 class to an interface)
 structs implement compile time interfaces via template duck typing
 (usually enforced via an if()).
 you could probably write a wrapper that introspected an interface and
 enforced that all members were implemented.
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Or we could get signatures, which are even better still!
Dec 29 2017
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Friday, 29 December 2017 at 13:08:38 UTC, rikki cattermole 
wrote:
 On 29/12/2017 12:59 PM, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:
 
 On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin 
 wrote:

 The problem is that interfaces are a runtime thing (e.g. you 
 can cast a
 class to an interface)
 structs implement compile time interfaces via template duck 
 typing
 (usually enforced via an if()).
 you could probably write a wrapper that introspected an 
 interface and
 enforced that all members were implemented.
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Or we could get signatures, which are even better still!
I was about to answer that interfaces could be used to define duck types conformity models but this would be a poor and useless addition, indeed, compared to signatures.
Dec 29 2017
prev sibling parent Mengu <mengukagan gmail.com> writes:
On Friday, 29 December 2017 at 13:08:38 UTC, rikki cattermole 
wrote:
 On 29/12/2017 12:59 PM, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:
 
 [...]
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Or we could get signatures, which are even better still!
+6666 for SML style signatures!
Dec 29 2017
prev sibling parent reply Laeeth Isharc <laeeth nospam.laeeth.com> writes:
On Friday, 29 December 2017 at 12:59:21 UTC, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:

 On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin 
 wrote:

 The problem is that interfaces are a runtime thing (e.g. you 
 can cast a
 class to an interface)
 structs implement compile time interfaces via template duck 
 typing
 (usually enforced via an if()).
 you could probably write a wrapper that introspected an 
 interface and
 enforced that all members were implemented.
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Atila does something like this https://code.dlang.org/packages/concepts
Jan 01 2018
next sibling parent rjframe <dlang ryanjframe.com> writes:
On Tue, 02 Jan 2018 00:54:13 +0000, Laeeth Isharc wrote:

 On Friday, 29 December 2017 at 12:59:21 UTC, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:

 I've actually thought about doing this to get rid of a bunch of if
 qualifiers in my function declarations. `static interface {}` compiles
 but doesn't [currently] seem to mean anything to the compiler, but
 could be a hint to the programmer that nothing will directly implement
 it; it's a compile-time interface. This would provide a more generic
 way of doing stuff like `isInputRange`, etc.
Atila does something like this https://code.dlang.org/packages/concepts
Thanks; I actually started skimming through his repositories a couple of days ago, but didn't see this. --Ryan
Jan 01 2018
prev sibling parent Chris M. <chrismohrfeld comcast.net> writes:
On Tuesday, 2 January 2018 at 00:54:13 UTC, Laeeth Isharc wrote:
 On Friday, 29 December 2017 at 12:59:21 UTC, rjframe wrote:
 On Fri, 29 Dec 2017 12:39:25 +0000, Nicholas Wilson wrote:

 [...]
I've actually thought about doing this to get rid of a bunch of if qualifiers in my function declarations. `static interface {}` compiles but doesn't [currently] seem to mean anything to the compiler, but could be a hint to the programmer that nothing will directly implement it; it's a compile-time interface. This would provide a more generic way of doing stuff like `isInputRange`, etc.
Atila does something like this https://code.dlang.org/packages/concepts
Glad you brought this up, looks quite useful.
Jan 02 2018
prev sibling next sibling parent thedeemon <dlang thedeemon.com> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:
 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?
It's a design decision. Look carefully at structs vs. classes here: https://dlang.org/spec/struct.html There is no virtual methods table (VMT) for structs, no inheritance. Structs have value semantics. A variable with a type of some interface implies it's a pointer, with reference semantics and a VMT.
Dec 29 2017
prev sibling next sibling parent Basile B. <b2.temp gmx.com> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:


 ----
 using System;

 interface IPrint
 {
     void Print();
 }

 struct MyStruct : IPrint
 {
     public void Print()
     {
         Console.WriteLine(ToString());
     }
 }

 public class Program
 {
     public static void Main()
     {
         MyStruct s = new MyStruct();
         s.Print();
     }
 }
 ----
 https://dotnetfiddle.net/lpXR1O

 But in D it doesn't appear possible.
 ----
 import std.stdio;

 interface IPrint
 {
     void print();
 }

 // Error: base classes are not allowed for struct, did you mean 
 ;?
 struct MyStruct : IPrint   // Error: base classes are not 
 allowed for struct, did you mean ;?
 {
     void print()
     {
         writeln("MyStruct");
     }
 }

 void main()
 {
 	MyStruct s;
     s.Print();
 }
 ----
 https://run.dlang.io/is/j4xwla

 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?

 Thanks for your insight,

 Mike
https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/ no vtable means for example that you cannot back to something after extracting the interface (with classes you can always get back to Object) as in D, struct should really only be used for a custom type with value semantic.
Dec 29 2017
prev sibling next sibling parent Random D user <no email.com> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:

 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?

 Thanks for your insight,

 Mike
I think it's deliberate, structs are just plain dumb value types. If I remember correctly I think Remedy's Binderoo C++ bindings implemented C++ inheritance on top of structs. You might want to look at that. Or you could do C-style "inheritance" and slap some D magic on top of that. Some pseudo code: struct Base { enum SubType subtype; int someBaseField; } struct Child1 { Base base; // Must be first int foo; } struct Child2 { Base base; float bar; } Base b; Child1 c1; Child2 c2; base_doSomething(Base* b); child1_doSomething(Child1* c1); child2_doSomething(Child2* c2); base_doSomething(cast(Base*)&c1); switch(base.subtype) { case Child1: child1_doSomething(cast(Child1*)&b); break; case Child2: child2_doSomething(cast(Child2*)&b); break; } // add some alias this and other d things to smooth things out.
Dec 29 2017
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/29/17 7:03 AM, Mike Franklin wrote:

 
 Is that simply because it hasn't been implemented or suggested yet for 
 D, or was there a deliberate design decision?
It was deliberate, but nothing says it can't actually be done. All an interface call is, is a thunk to grab the actual object, and then a call to the appropriate function from a static vtable. It's pretty doable to make a fake interface. In fact, I'm pretty sure someone did just this, I have no idea how far back in the forums to search, but you can probably find it. Now, it would be nicer if the language itself supported it. And I don't see any reason why it couldn't be supported. The only issue I think could be an ABI difference between member calls of structs and classes, but I think they are the same. -Steve
Dec 30 2017
parent flamencofantasy <flamencofantasy gmail.com> writes:
On Saturday, 30 December 2017 at 16:23:05 UTC, Steven 
Schveighoffer wrote:
 On 12/29/17 7:03 AM, Mike Franklin wrote:

 
 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?
It was deliberate, but nothing says it can't actually be done. All an interface call is, is a thunk to grab the actual object, and then a call to the appropriate function from a static vtable. It's pretty doable to make a fake interface. In fact, I'm pretty sure someone did just this, I have no idea how far back in the forums to search, but you can probably find it. Now, it would be nicer if the language itself supported it. And I don't see any reason why it couldn't be supported. The only issue I think could be an ABI difference between member calls of structs and classes, but I think they are the same. -Steve
Don't forget to implement boxing/unboxing and then write a long blog post on all the dangers and negative effects of using interfaces with structs.
Jan 02 2018
prev sibling parent Meta <jared771 gmail.com> writes:
On Friday, 29 December 2017 at 12:03:59 UTC, Mike Franklin wrote:


 ----
 using System;

 interface IPrint
 {
     void Print();
 }

 struct MyStruct : IPrint
 {
     public void Print()
     {
         Console.WriteLine(ToString());
     }
 }

 public class Program
 {
     public static void Main()
     {
         MyStruct s = new MyStruct();
         s.Print();
     }
 }
 ----
 https://dotnetfiddle.net/lpXR1O

 But in D it doesn't appear possible.
 ----
 import std.stdio;

 interface IPrint
 {
     void print();
 }

 // Error: base classes are not allowed for struct, did you mean 
 ;?
 struct MyStruct : IPrint   // Error: base classes are not 
 allowed for struct, did you mean ;?
 {
     void print()
     {
         writeln("MyStruct");
     }
 }

 void main()
 {
 	MyStruct s;
     s.Print();
 }
 ----
 https://run.dlang.io/is/j4xwla

 Is that simply because it hasn't been implemented or suggested 
 yet for D, or was there a deliberate design decision?

 Thanks for your insight,

 Mike
You want wrap: https://dlang.org/phobos/std_typecons.html#wrap
Jan 01 2018