digitalmars.D.learn - why can't structs implement interfaces?
- Saaa (2/2) Nov 24 2009 struct S : Pos {}
- Moritz Warning (5/7) Nov 24 2009 The struct would need an additional pointer
- bearophile (4/6) Nov 24 2009 In the meantime this can be done with a template mixin, where the templa...
- Saaa (6/13) Nov 24 2009 I wanted to do something like this:
- Bill Baxter (16/32) Nov 24 2009 Yeh, that's never going to work because that's acting as a dynamic
- Lutger (5/45) Nov 24 2009 I can confirm that it is not possible with alias this.
- Saaa (5/40) Nov 24 2009 Why is a hidden pointer necessary? (Just curious :)
- Bill Baxter (8/24) Nov 24 2009 I think it could be done with a different implementation of interfaces
- Daniel Keep (24/52) Nov 24 2009 (This is all off the top of my head.)
-
Bill Baxter
(12/25)
Nov 24 2009
-
Saaa
(5/6)
Nov 24 2009
- bearophile (12/15) Nov 24 2009 In D2 if you define a struct inside a function it (in theory) grows an h...
- Bill Baxter (14/18) Nov 24 2009 I really think some kind of static interface (concept) support is
- bearophile (6/12) Nov 24 2009 I agree, this looks like something that can be added to D even after D2 ...
- Don (5/20) Nov 25 2009 That's been requested many times. I posted a patch to Walter to do
- Lars T. Kyllingstad (3/34) Nov 25 2009 What's the bugzilla number? Should be upvoted.
- bearophile (15/16) Nov 25 2009 I think he refers to this one (searching something in Bugzilla seems a g...
- bearophile (4/8) Nov 25 2009 If your patch is well done, works with LDC too, I see no reason to refus...
- Don (4/11) Nov 25 2009 Please don't do that just yet. It's something that can wait until the D2...
- bearophile (4/7) Nov 25 2009 OK :-) You are right, as usual.
- Lutger (6/10) Nov 24 2009 Because structs are meant to be value types and thus do not implement
- Rory McGuire (3/8) Nov 25 2009 Why do you want to use a struct for that, rather than a class?
- wakko (53/56) Nov 25 2009 It's not and structures have no vtable... fortunately.
On Tue, 24 Nov 2009 21:55:02 +0100, Saaa wrote:struct S : Pos {} Why is this not possible?The struct would need an additional pointer for a dispatch table in case you want to have class semantics. If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.
Nov 24 2009
Moritz Warning:If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want. Bye, bearophile
Nov 24 2009
bearophile wrote:Moritz Warning:I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =[new C(), s ];If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want. Bye, bearophile
Nov 24 2009
On Tue, Nov 24, 2009 at 2:49 PM, Saaa <empty needmail.com> wrote:bearophile wrote:Yeh, that's never going to work because that's acting as a dynamic polymorphic interaface. Referring polymorphically to a struct like that pretty much makes it not a struct anymore, and requires having the hidden pointer to a vtable that was mentioned. That's what classes are for. In D2 you can use "alias this" inside a class to forward things to the struct, though. Something like this: class ClassWrapper(S) : I { S _impl; alias _impl this; } But I somehow doubt DMD will consider methods handled by S as being an implementation of the interface. So you'll need explicit forwarding. --bbMoritz Warning:I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =[new C(), s ];If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want. Bye, bearophile
Nov 24 2009
Bill Baxter wrote:On Tue, Nov 24, 2009 at 2:49 PM, Saaa <empty needmail.com> wrote:I can confirm that it is not possible with alias this. Somewhat related, template mixins can add virtual methods: template T() { /*implementation of I*/ } class C : I { mixin T!(); } // adds methods in T!() as virtual methodsbearophile wrote:Yeh, that's never going to work because that's acting as a dynamic polymorphic interaface. Referring polymorphically to a struct like that pretty much makes it not a struct anymore, and requires having the hidden pointer to a vtable that was mentioned. That's what classes are for. In D2 you can use "alias this" inside a class to forward things to the struct, though. Something like this: class ClassWrapper(S) : I { S _impl; alias _impl this; } But I somehow doubt DMD will consider methods handled by S as being an implementation of the interface. So you'll need explicit forwarding. --bbMoritz Warning:I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =[new C(), s ];If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want. Bye, bearophile
Nov 24 2009
Bill Baxter wrote:On Tue, Nov 24, 2009 at 2:49 PM, Saaa <empty needmail.com> wrote:Why is a hidden pointer necessary? (Just curious :) My simplistic view was like this: i[1] would just hold the location of s and s would be checked to have all it needs to be an I.bearophile wrote:Yeh, that's never going to work because that's acting as a dynamic polymorphic interaface. Referring polymorphically to a struct like that pretty much makes it not a struct anymore, and requires having the hidden pointer to a vtable that was mentioned. That's what classes are for.Moritz Warning:I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =[new C(), s ];If you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want. Bye, bearophileIn D2 you can use "alias this" inside a class to forward things to the struct, though. Something like this: class ClassWrapper(S) : I { S _impl; alias _impl this; } But I somehow doubt DMD will consider methods handled by S as being an implementation of the interface. So you'll need explicit forwarding. --bb
Nov 24 2009
On Tue, Nov 24, 2009 at 3:09 PM, Saaa <empty needmail.com> wrote:I think it could be done with a different implementation of interfaces from the one D uses, one based on "fat pointers". With that design an I referring to an S would be a "fat pointer", one pointer pointing to the S and one pointing to S's table of function pointers (vtable) for the I interface. That's not how D does it AFAIR, but I don't actually recall how D does it. --bbWhy is a hidden pointer necessary? (Just curious :) My simplistic view was like this: i[1] would just hold the location of s and s would be checked to have all it needs to be an I.I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =3D[new C(), s ];Yeh, that's never going to work because that's acting as a dynamic polymorphic interaface. =A0Referring polymorphically to a struct like that pretty much makes it not a struct anymore, and requires having the hidden pointer to a vtable that was mentioned. =A0That's what classes are for.
Nov 24 2009
Bill Baxter wrote:On Tue, Nov 24, 2009 at 3:09 PM, Saaa <empty needmail.com> wrote:(This is all off the top of my head.) In D, interfaces are pointers to the vtable which implements the interface for a particular class. In order to actually get the "this" reference, D stores a pointer to the class' InterfaceInfo (or something) for that interface in the first slot of the vtable. This InterfaceInfo indicates how far from the start of an instance the pointer to the vtable is contained. To get "this", you take the pointer to the interface vtable and subtract this offset. This is why interfaces cannot be implemented by structs in D: it would require structs to grow magical hidden fields, which is explicitly against the stated purpose of structs: plain old data. Even then, there's a worse problem. All interfaces can be cast to Object, and then upcast to any valid class. This is done via the use of the first slot of the object's vtable, which contains the ClassInfo. But if you allow structs as interfaces, you're suddenly in the position where you might not actually have an object at all. If you tried to cast a struct to an Object, it might not actually fail; if you're lucky, you'll get a segfault. The only solution there is to give structs a vtable. At which point, congratulations, you've just re-invented classes. To allow structs to implement interfaces would require redesigning how interfaces are actually implemented. You'd probably have to also redesign RTTI as well, object casting, etc.I think it could be done with a different implementation of interfaces from the one D uses, one based on "fat pointers". With that design an I referring to an S would be a "fat pointer", one pointer pointing to the S and one pointing to S's table of function pointers (vtable) for the I interface. That's not how D does it AFAIR, but I don't actually recall how D does it. --bbWhy is a hidden pointer necessary? (Just curious :) My simplistic view was like this: i[1] would just hold the location of s and s would be checked to have all it needs to be an I.I wanted to do something like this: class C : I {}; struct S : I {}; S s; I[] i =[new C(), s ];Yeh, that's never going to work because that's acting as a dynamic polymorphic interaface. Referring polymorphically to a struct like that pretty much makes it not a struct anymore, and requires having the hidden pointer to a vtable that was mentioned. That's what classes are for.
Nov 24 2009
On Tue, Nov 24, 2009 at 4:38 PM, Daniel Keep <daniel.keep.lists gmail.com> wrote:(This is all off the top of my head.)<nice explanation snipped -- thanks>Even then, there's a worse problem. =A0All interfaces can be cast to Object, and then upcast to any valid class. =A0This is done via the use o=fthe first slot of the object's vtable, which contains the ClassInfo.Well, except for those dreaded "IUnknown" COM interfaces.But if you allow structs as interfaces, you're suddenly in the position where you might not actually have an object at all. =A0If you tried to cast a struct to an Object, it might not actually fail; if you're lucky, you'll get a segfault.Same as with IUnknown interfaces.The only solution there is to give structs a vtable. =A0At which point, congratulations, you've just re-invented classes. To allow structs to implement interfaces would require redesigning how interfaces are actually implemented. =A0You'd probably have to also redesign RTTI as well, object casting, etc.But with good enough introspection, it should be possible to make automatic class wrappers for structs that implement an interface by forwarding to the struct. That's probably mostly doable now, though probably with a frightening assortment method signature string parsing and mixins. --bb
Nov 24 2009
Bill Baxter wrote: <daniel.keep.lists gmail.com> wrote:(This is all off the top of my head.)<nice explanation snipped -- thanks> < snipped --bb > Thanks for all the explanations!
Nov 24 2009
Daniel Keep:This is why interfaces cannot be implemented by structs in D: it would require structs to grow magical hidden fields, which is explicitly against the stated purpose of structs: plain old data.In D2 if you define a struct inside a function it (in theory) grows an hidden field, see Nested Structs here: http://www.digitalmars.com/d/2.0/struct.html I have written in theory because in practice the size is the same :-) And the following code doesn't compile, static structs are not implemented yet it seems: void foo() { static struct Inner { int x; } } Walter needs an automatic way to test code snippets inside the docs... Bye, bearophile
Nov 24 2009
On Tue, Nov 24, 2009 at 2:36 PM, bearophile <bearophileHUGS lycos.com> wrote:Moritz Warning:I really think some kind of static interface (concept) support is going to be necessary eventually. In terms of functionality, static asserts and "isInterfaceSupported()" methods are OK. But the usability is not great. In particular there's not a good way for the compiler to give good error messages about why a concept is not satisfied by a particular type. I tried to come up with a way to do that given access to compiler error messages, but the result looks rather like attempts to do runtime inheritance in C. The good thing is that since most of the machinery is there, the actual compiler changes required would mostly be just rewrites of new syntax in terms of existing functionality. --bbIf you only what a contract that certain functions are implemented, then it just need to be implemented in the compiler frontend.In the meantime this can be done with a template mixin, where the template statically asserts the presence of the functions/fields you want.
Nov 24 2009
Bill Baxter:The good thing is that since most of the machinery is there, the actual compiler changes required would mostly be just rewrites of new syntax in terms of existing functionality.I agree, this looks like something that can be added to D even after D2 comes out of alpha. But Andrei warns us that here it's easy to overdo the design. So I think that keeping usability low (= keeping things handmade and low-tech) can be better than a Byzantine and limited design.In particular there's not a good way for the compiler to give good error messages about why a concept is not satisfied by a particular type.Time ago I have asked for a "small" compiler feature: when a function/class template creates a compile-time error (because some of the code inside it is not compatible with the specific type given to the template) I'd like the D compiler to act as GCC, telling me not just where there is the error inside the template, but also and *before* that error message to show me the line of where the template is instantiated. This is another small feature that can be added after D2 "finalization". Bye, bearophile
Nov 24 2009
bearophile wrote:Bill Baxter:That's been requested many times. I posted a patch to Walter to do exactly that. It was beautiful. It detected recursive template expansions, and gave really nice error messages. Silently rejected. Sigh.The good thing is that since most of the machinery is there, the actual compiler changes required would mostly be just rewrites of new syntax in terms of existing functionality.I agree, this looks like something that can be added to D even after D2 comes out of alpha. But Andrei warns us that here it's easy to overdo the design. So I think that keeping usability low (= keeping things handmade and low-tech) can be better than a Byzantine and limited design.In particular there's not a good way for the compiler to give good error messages about why a concept is not satisfied by a particular type.Time ago I have asked for a "small" compiler feature: when a function/class template creates a compile-time error (because some of the code inside it is not compatible with the specific type given to the template) I'd like the D compiler to act as GCC, telling me not just where there is the error inside the template, but also and *before* that error message to show me the line of where the template is instantiated. This is another small feature that can be added after D2 "finalization".
Nov 25 2009
Don wrote:bearophile wrote:What's the bugzilla number? Should be upvoted. -LarsBill Baxter:That's been requested many times. I posted a patch to Walter to do exactly that. It was beautiful. It detected recursive template expansions, and gave really nice error messages. Silently rejected. Sigh.The good thing is that since most of the machinery is there, the actual compiler changes required would mostly be just rewrites of new syntax in terms of existing functionality.I agree, this looks like something that can be added to D even after D2 comes out of alpha. But Andrei warns us that here it's easy to overdo the design. So I think that keeping usability low (= keeping things handmade and low-tech) can be better than a Byzantine and limited design.In particular there's not a good way for the compiler to give good error messages about why a concept is not satisfied by a particular type.Time ago I have asked for a "small" compiler feature: when a function/class template creates a compile-time error (because some of the code inside it is not compatible with the specific type given to the template) I'd like the D compiler to act as GCC, telling me not just where there is the error inside the template, but also and *before* that error message to show me the line of where the template is instantiated. This is another small feature that can be added after D2 "finalization".
Nov 25 2009
Lars T. Kyllingstad:What's the bugzilla number? Should be upvoted.I think he refers to this one (searching something in Bugzilla seems a good way to spend a morning): http://d.puremagic.com/issues/show_bug.cgi?id=2816 In the comment 9, instead of: bug.d(2): Error: static assert (0) is false bug.d(9): instantiatied from here: bar!() bug.d(14): 100 recursive instantiations from here: foo!(196) bug.d(19): 253 recursive instantiations from here: baz!(300) Someone may prefer them listed in inverted order: bug.d(19): ... bug.d(14): ... bug.d(9): ... bug.d(2): ... Bye, bearophile
Nov 25 2009
Don:That's been requested many times. I posted a patch to Walter to do exactly that. It was beautiful. It detected recursive template expansions, and gave really nice error messages. Silently rejected. Sigh.If your patch is well done, works with LDC too, I see no reason to refuse this feature even for D1, it doesn't change the language and just makes debugging simpler. So let's not surrender yet. How much time ago Walter has refused this patch? Lately Walter is more receptive for your patches. I can create a new thread about this in the main D NG. If 8+ persons say they want this patch, and it works correctly, then Walter can change his mind. Bye, bearophile
Nov 25 2009
bearophile wrote:Don:Please don't do that just yet. It's something that can wait until the D2 stuff is finished. It can be added at any time. Some of the other things are urgent.That's been requested many times. I posted a patch to Walter to do exactly that. It was beautiful. It detected recursive template expansions, and gave really nice error messages. Silently rejected. Sigh.If your patch is well done, works with LDC too, I see no reason to refuse this feature even for D1, it doesn't change the language and just makes debugging simpler. So let's not surrender yet. How much time ago Walter has refused this patch? Lately Walter is more receptive for your patches. I can create a new thread about this in the main D NG. If 8+ persons say they want this patch, and it works correctly, then Walter can change his mind.
Nov 25 2009
Don:Please don't do that just yet. It's something that can wait until the D2 stuff is finished. It can be added at any time. Some of the other things are urgent.OK :-) You are right, as usual. Bye, bearophile
Nov 25 2009
Saaa wrote:struct S : Pos {} Why is this not possible?Because structs are meant to be value types and thus do not implement dynamic polymorphism, which is what interfaces are used for. It is not necessary though, classes in C++ are almost the same as structs for example, but there are problems with that design.
Nov 24 2009
"Saaa" <empty needmail.com> wrote:struct S : Pos {} Why is this not possible?Why do you want to use a struct for that, rather than a class?
Nov 25 2009
Saaa a écrit :struct S : Pos {} Why is this not possible?It's not and structures have no vtable... fortunately. But, could it be a good idea to use the "inheritance operator" to do some kind of static inheritance like we do with mixins or to force implementation at compile-time ? 1. inheriting from an interfaces would force function implementation at compile time: interface IFoo { void foo(); } // Would not compile // "Struct S static interface function IFoo.foo isn't implemented" struct S : IFoo {} // Would compile struct S : IFoo { void foo() {} } 2. inheriting from a structure would do some kind a mixin. struct S1 { void foo(); static void bar(); } struct S2 : S1 {} S1.bar(); S1 a; a.foo(); a.bar(); 3. class and structs could share interfaces for compile time function name resolution. I think this already work using untyped template arguments. interface IFoo { void foo(); } class C : IFoo // dynamic inheritance { void foo() { } } struct S : IFoo // static inheritance { void foo() { } } class Bar(IFoo FOO) { void bar(FOO thing) { thing.foo(); } } 4. casting could be forbidden OR : struct A { int a; } struct B : A {} // B implements "int a" as in 2 A a; B b = a; // would do something like b.a = a.a B b; A a = b; // would do something like a.a = b.a -- AF
Nov 25 2009