digitalmars.D - Vtable for virtual functions in D
- Henrik (16/16) Mar 06 2018 Does anyone know if D is using the vtable implementation for
- sarn (6/22) Mar 06 2018 D uses vtables.
- Patrick Schluter (6/22) Mar 07 2018 p0nce[1] has a link to an excellent article explaining in detail
- Patrick Schluter (6/14) Mar 07 2018 D is the perfect fit for your description. Converting java to D
- Guillaume Piolat (23/40) Mar 07 2018 Without measuring, I'd tend to agree with you that it should be
- Henrik (24/24) Mar 07 2018 Hi everyone,
- H. S. Teoh (49/52) Mar 07 2018 [...]
- Laeeth Isharc (5/12) Apr 02 2018 "Are there any plans to support the direct inclusion [of] C
- sarn (12/14) Mar 07 2018 When I wrote Xanthe a year ago, I rolled my own classes using
- Mike Franklin (6/11) Mar 07 2018 Nice! I was thinking about something almost exactly like this
- sarn (6/11) Mar 08 2018 I didn't realise there was any interest. Sure, I'll try to make
- sarn (5/14) Apr 02 2018 I decided to pull some basic background info about vtables, etc,
- Mike Franklin (3/18) Apr 02 2018 Nice! Looking forward to part 2.
- Kagamin (4/8) Apr 03 2018 You can use COM interfaces. You'll still need to build vtable by
- Guillaume Piolat (2/16) Mar 08 2018 Very interesting
- Henrik (56/70) Mar 08 2018 This is great, it is exactly what I was hoping for! The
- sarn (19/21) Mar 08 2018 You can make things slightly better by putting @nogc in the
- Manu (6/7) Mar 09 2018 @nogc in the global scope does not propagate inside the class (this
- Mike Franklin (6/14) Apr 02 2018 What specifically do you think should be changed in the language
- sarn (6/14) Apr 03 2018 Sorry, I'll go into the details in my blog post, but what that
- Kagamin (5/10) Apr 03 2018 You can use address of vtable as type id. Unique and doesn't need
Does anyone know if D is using the vtable implementation for virtual functions just like most C++ compilers? If yes, can someone explain the advantages of this strategy? A function pointer in C is regarded as expensive because of missing inlining, but a double indirection through a vtable just looks insane - if there aren't really good reasons for such an implementation. Does it make class inheritance or class polymorphism much simpler to implement or what is the reason? I have worked with C in embedded systems for many years now, and for our modern Linux systems we are using a combination of C and Java today. Java for parts where memory safety is more important than speed/determinism, and C for the critical real time parts. There should exist a language between these worlds, where we can achieve memory safety at relatively small costs. C++ is not really an alternative, and D looks much more pleasant for us C programmers than for example Rust.
Mar 06 2018
On Tuesday, 6 March 2018 at 21:20:22 UTC, Henrik wrote:Does anyone know if D is using the vtable implementation for virtual functions just like most C++ compilers? If yes, can someone explain the advantages of this strategy? A function pointer in C is regarded as expensive because of missing inlining, but a double indirection through a vtable just looks insane - if there aren't really good reasons for such an implementation. Does it make class inheritance or class polymorphism much simpler to implement or what is the reason? I have worked with C in embedded systems for many years now, and for our modern Linux systems we are using a combination of C and Java today. Java for parts where memory safety is more important than speed/determinism, and C for the critical real time parts. There should exist a language between these worlds, where we can achieve memory safety at relatively small costs. C++ is not really an alternative, and D looks much more pleasant for us C programmers than for example Rust.D uses vtables. It's a tradeoff between having double indirection and bloating each instance with the function pointers. In cases where bloating isn't a problem, I just explicitly add normal function pointer members.
Mar 06 2018
On Tuesday, 6 March 2018 at 21:20:22 UTC, Henrik wrote:Does anyone know if D is using the vtable implementation for virtual functions just like most C++ compilers? If yes, can someone explain the advantages of this strategy? A function pointer in C is regarded as expensive because of missing inlining, but a double indirection through a vtable just looks insane - if there aren't really good reasons for such an implementation. Does it make class inheritance or class polymorphism much simpler to implement or what is the reason? I have worked with C in embedded systems for many years now, and for our modern Linux systems we are using a combination of C and Java today. Java for parts where memory safety is more important than speed/determinism, and C for the critical real time parts. There should exist a language between these worlds, where we can achieve memory safety at relatively small costs. C++ is not really an alternative, and D looks much more pleasant for us C programmers than for example Rust.p0nce[1] has a link to an excellent article explaining in detail how the implementation of the vtable, single inheritance with interfaces work. The article isn't about D per se but D classes use the same mechanism. [1]: https://p0nce.github.io/d-idioms/#Inside-the-D-Object-Model
Mar 07 2018
On Tuesday, 6 March 2018 at 21:20:22 UTC, Henrik wrote:I have worked with C in embedded systems for many years now, and for our modern Linux systems we are using a combination of C and Java today. Java for parts where memory safety is more important than speed/determinism, and C for the critical real time parts. There should exist a language between these worlds, where we can achieve memory safety at relatively small costs. C++ is not really an alternative, and D looks much more pleasant for us C programmers than for example Rust.D is the perfect fit for your description. Converting java to D can be surprisingly easy, unless one used a lot of libraries which are quite different. As for C, I'm of the opinion that D is much more respectful of its C heritage than even C++ is.
Mar 07 2018
On Tuesday, 6 March 2018 at 21:20:22 UTC, Henrik wrote:Does anyone know if D is using the vtable implementation for virtual functions just like most C++ compilers?Yes, except without multiple inheritance / virtual inheritance.If yes, can someone explain the advantages of this strategy? A function pointer in C is regarded as expensive because of missing inlining, but a double indirection through a vtable just looks insane - if there aren't really good reasons for such an implementation.Without measuring, I'd tend to agree with you that it should be more expensive (let's not use the arguments that "this part of memory will be hot" which means it will take a share of cache that could go to something else). I guess the reason is simple: low overhead with regards to layout (only a pointer gets added to each instance). The v-table point itself to TypeInfo so you hide this pointer too. TypeInfo is a bit like RTTI in the C++ world. Note that even in C++ if a virtual call is expensive in the profiler you can switch on a type tag and devirtualize by casting (virtual functions are only expensive when the runtime type is unknown to the compiler). The alternative layout is to embed the v-table in each object when priming a new object, and having the TypeInfo pointer in each class instance in addition to a pointer for each virtual method.Does it make class inheritance or class polymorphism much simpler to implement or what is the reason?I don't know. Intuitively it doesn't seem much easier with v-table. COM objects are expected to have such a layout too.I have worked with C in embedded systems for many years now, and for our modern Linux systems we are using a combination of C and Java today. Java for parts where memory safety is more important than speed/determinism, and C for the critical real time parts. There should exist a language between these worlds, where we can achieve memory safety at relatively small costs. C++ is not really an alternative, and D looks much more pleasant for us C programmers than for example Rust.If you know enough D maybe you can implement your own virtual functions on top of D structs. It seems no one has made it yet.
Mar 07 2018
Hi everyone, thank you all for your great answers. I'm playing around with nogc right now, and it looks really promising. Strings and static arrays all seem to be located on the stack, which is so much better compared to std::string and std::vector in C++. The double indirection for virtual functions bother me, and it isn't getting better with all methods being virtual by default - I guess I'll be writing the keyword "final" very intensively in all my programs. I would also gladly pay some bytes in pointer bloat to have my virtual functions speed up. Strange that D kept the vtable approach when breaking with C++. I know that D concentrated much on C++ compatibility a while ago. Are there any plans to support the direct inclusion on C header files? Many important libraries like ICU have C interfaces even when written in C++. The direct support of C headers would be very convenient in migrating parts of C/C++ projects to D. It would also open up POSIX which is used extensively in our work. This looks great: https://github.com/D-Programming-Deimos/ but it must be tedious to keep such files up to date. Despite the point where I'm complaining, I must say that D looks very impressive. Beautiful syntax, large standard library, and standardized inline assembler (Thank you!). I'll definitely try to find a suitable project to try out D under serious conditions.
Mar 07 2018
On Wed, Mar 07, 2018 at 09:14:12PM +0000, Henrik via Digitalmars-d wrote: [...]The direct support of C headers would be very convenient in migrating parts of C/C++ projects to D. It would also open up POSIX which is used extensively in our work.[...] There's already core.sys.posix.*, which are POSIX headers translated into D, and which you can import and use right away. E.g.: import core.sys.posix.unistd; char[1024] buf; int fd = open("/tmp/file", O_RDONLY); auto len = read(fd, buf.ptr, buf.length); ... close(fd); Similarly, C standard library functions are directly available via core.stdc.*: import core.stdc.stdlib; void* buf = malloc(1024); ... // use buf here free(buf); In principle, although direct support of C headers is not supported (yet?), it's pretty easy to declare C functions in D and then just call it directly, e.g.: // Declare C function here extern(C) size_t strlen(const(char)* s); void main() { import std.string : toStringz; // Call here auto len = strlen("blah blah".toStringz); } In the above example I purposely used std.string to showcase how easy it is to interoperate with C API functions, with toStringz and fromStringz providing convenient conversions to/from C's char* strings. The only wrinkle here is that toStringz may allocate (because D strings are not null-terminated in general), so cannot be used in nogc code. However, D string *literals* are always null-terminated, so the above code could actually be replaced with just: auto len = strlen("blah blah".ptr); and it will work in nogc as well. Just be careful not to do that with non-literal strings (or append a null manually and then it should be safe). The trouble with general C headers is that sometimes complicated macros are used, and D does not come with a C macro processor, so it is tricky to interface with those kinds of headers. Still, if your code is not directly dependent on the macros, you could just run the header through a C preprocessor and then translate the C prototypes into D. (There are some cases for which this may not be so straightforward, but generally you should be able to get quite far this way.) T -- Caffeine underflow. Brain dumped.
Mar 07 2018
On Wednesday, 7 March 2018 at 21:14:12 UTC, Henrik wrote:Many important libraries like ICU have Cinterfaces even when written in C++. The direct support of C headers would be very convenient in migrating parts of C/C++ projects to D. It would also open up POSIX which is used extensively in our work. This looks great: https://github.com/D-Programming-Deimos/ but it must be tedious to keep such files up to date."Are there any plans to support the direct inclusion [of] C header files?" Yes, very shortly, as an extra build step. Watch this space.
Apr 02 2018
On Wednesday, 7 March 2018 at 12:49:40 UTC, Guillaume Piolat wrote:If you know enough D maybe you can implement your own virtual functions on top of D structs. It seems no one has made it yet.When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.) Henrik: you might be interested in this post I wrote about making that: https://theartofmachinery.com/2017/02/28/bare_metal_d.html NB: things are moving fast and some things have already improved since then.
Mar 07 2018
On Wednesday, 7 March 2018 at 22:02:17 UTC, sarn wrote:When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.)Nice! I was thinking about something almost exactly like this recently since 2.079.0 has features to further decouple the language from the runtime. It would be nice to read a blog post about this technique. Mike
Mar 07 2018
On Thursday, 8 March 2018 at 04:37:08 UTC, Mike Franklin wrote:Nice! I was thinking about something almost exactly like this recently since 2.079.0 has features to further decouple the language from the runtime. It would be nice to read a blog post about this technique. MikeI didn't realise there was any interest. Sure, I'll try to make it one of my next few posts. And, yeah, the new 2.079 release has made some very significant improvements. I'm still experimenting to find out what's possible now.
Mar 08 2018
On Thursday, 8 March 2018 at 22:07:24 UTC, sarn wrote:On Thursday, 8 March 2018 at 04:37:08 UTC, Mike Franklin wrote:I decided to pull some basic background info about vtables, etc, into its own post. I'll write about taking advantage of alias this and template metaprogramming in a later post. https://theartofmachinery.com/2018/04/02/inheritance_and_polymorphism.htmlNice! I was thinking about something almost exactly like this recently since 2.079.0 has features to further decouple the language from the runtime. It would be nice to read a blog post about this technique. MikeI didn't realise there was any interest. Sure, I'll try to make it one of my next few posts.
Apr 02 2018
On Monday, 2 April 2018 at 07:02:07 UTC, sarn wrote:On Thursday, 8 March 2018 at 22:07:24 UTC, sarn wrote:Nice! Looking forward to part 2. MikeOn Thursday, 8 March 2018 at 04:37:08 UTC, Mike Franklin wrote:I decided to pull some basic background info about vtables, etc, into its own post. I'll write about taking advantage of alias this and template metaprogramming in a later post. https://theartofmachinery.com/2018/04/02/inheritance_and_polymorphism.htmlNice! I was thinking about something almost exactly like this recently since 2.079.0 has features to further decouple the language from the runtime. It would be nice to read a blog post about this technique. MikeI didn't realise there was any interest. Sure, I'll try to make it one of my next few posts.
Apr 02 2018
On Monday, 2 April 2018 at 07:02:07 UTC, sarn wrote:I decided to pull some basic background info about vtables, etc, into its own post. I'll write about taking advantage of alias this and template metaprogramming in a later post. https://theartofmachinery.com/2018/04/02/inheritance_and_polymorphism.htmlYou can use COM interfaces. You'll still need to build vtable by hand, but at least you'll have some syntax sugar at the call site if you don't have multiple inheritance.
Apr 03 2018
On Wednesday, 7 March 2018 at 22:02:17 UTC, sarn wrote:On Wednesday, 7 March 2018 at 12:49:40 UTC, Guillaume Piolat wrote:Very interestingIf you know enough D maybe you can implement your own virtual functions on top of D structs. It seems no one has made it yet.When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.) Henrik: you might be interested in this post I wrote about making that: https://theartofmachinery.com/2017/02/28/bare_metal_d.html NB: things are moving fast and some things have already improved since then.
Mar 08 2018
On Wednesday, 7 March 2018 at 22:02:17 UTC, sarn wrote:On Wednesday, 7 March 2018 at 12:49:40 UTC, Guillaume Piolat wrote:This is great, it is exactly what I was hoping for! The core.sys.posix is also pure gold. I'm obviously not the first person here to have an interest in this topic. Really pleasant reading! In my view; the evolution of programming languages skipped at and similar languages. If D could form an natural next step after C, with a favorable tradeoff between memory safety and performance, it could really change the embedded software industry. C11 + Valgrind/AdressSanitizer etc are great to develop fast reliable software, and most universities here in Europe - from my experience at least - are teaching C, but not as much C++. I like C, but it really only dominates because everyone else performs so poorly in embedded/system environments. I should probably move to the learn category for the next part, but I can post one example at least. It is my first naive step of creating a RAII struct dummy, and check my program for memory corruptions; two things that C cannot do. It all works good, but why do I have to put the nogc on the constructor and destructor separately? import std.stdio; import core.exception; nogc: struct Nice { int a; this(int a) nogc { this.a = a; puts("A"); } ~this() nogc { puts("B"); } } void TestStruct() { //char *c = new char(); Nice n = Nice(55); } void TestIndexOutOfBounds(int i) { int a[100] = void; a[0] = a[i]; } void main(string[ ] args) { try { TestStruct(); TestIndexOutOfBounds(100); } catch(core.exception.RangeError e) { puts("Sloppy work! Enter safety mode!"); } }If you know enough D maybe you can implement your own virtual functions on top of D structs. It seems no one has made it yet.When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.) Henrik: you might be interested in this post I wrote about making that: https://theartofmachinery.com/2017/02/28/bare_metal_d.html NB: things are moving fast and some things have already improved since then.
Mar 08 2018
On Thursday, 8 March 2018 at 22:56:27 UTC, Henrik wrote:why do I have to put the nogc on the constructor and destructor separately?You can make things slightly better by putting nogc in the struct itself: struct S { nogc: void member1() { } void member2() { } } But, yeah, this is a current pain point: attributes aren't "deep". Maybe one day we'll have a syntax for applying attributes recursively, but I think it's blocking on the lack of a syntax for inverting an attribute. (I.e., a way to declare an impure/gc/whatever thing inside a region that's declared pure/nogc/whatever.)
Mar 08 2018
On 8 March 2018 at 14:56, Henrik via Digitalmars-d <digitalmars-d puremagic.com> wrote:It all works good, but why do I have to put the nogc on the constructor and destructor separately?nogc in the global scope does not propagate inside the class (this could lead to serious problems). You can use ` nogc:` at the top of your class to make all class contents nogc too.
Mar 09 2018
On Wednesday, 7 March 2018 at 22:02:17 UTC, sarn wrote:When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.)I'm curious about this comment in the code:Unfortunately, "protected" doesn't work, so a lot of members end up being public. This seems to just be an oversight in the language, so maybe it will change in future versions of D.What specifically do you think should be changed in the language to support your idea? Thanks, Mike
Apr 02 2018
On Tuesday, 3 April 2018 at 00:22:52 UTC, Mike Franklin wrote:I'm curious about this comment in the code:Sorry, I'll go into the details in my blog post, but what that comment is talking about is this: D has a "protected" specifier for classes, just like C++, but not one for structs - struct members can only be private or public. This is because D structs don't natively support inheritance.Unfortunately, "protected" doesn't work, so a lot of members end up being public. This seems to just be an oversight in the language, so maybe it will change in future versions of D.What specifically do you think should be changed in the language to support your idea? Thanks, Mike
Apr 03 2018
On Wednesday, 7 March 2018 at 22:02:17 UTC, sarn wrote:When I wrote Xanthe a year ago, I rolled my own classes using alias this and explicit vtables: https://gitlab.com/sarneaud/xanthe/blob/master/src/game/rigid_body.d#L15 (I did this because normal D classes use the druntime library, and Xanthe was an experiment in not using the D runtime at all.)You can use address of vtable as type id. Unique and doesn't need CTFE. alias TypeId=immutable(VTable*); alias type_id=_vtable;
Apr 03 2018