Walter Bright at NWCPP: Interfacing D to Legacy C++ Code.
D is a systems language with a similar target user group to Rust. The general position on why they’re working on interfacing to C++ is best summed up with this line: “Because we keep hearing ‘I want to use D, but I’m trapped by my C++ code!’. … Having a C interface isn’t good enough.” Rust is, more than likely, going to hit the same complaints, so what D does in this space seems very relevant to Rust. A quick summary:
- All efforts are geared toward just linking to C++ code: i.e. matching C++'s name mangling, layout and calling conventions.
- D has to special-case it’s support on a per-compiler basis. Has
extern (C++)
. - Only a few “magic” types such as a
__c_long
struct which has special mangling:long
in C++ has a unique mangling, but no D equivalent. This is a byproduct of D having integral types which are similar to Rust’s: they have defined sizes. - Namespaces handled by extension to
extern
syntax:extern (C++, N.M)
= “C++ declaration in theN::M
namespace”. - Struct layout: already matches, due to common C ancestry.
- Struct static member functions: fine.
- Virtual functions:
extern (C++)
on a class, or inherit fromIUnknown
for COM classes. - Value/reference type duality for UDTs in C++: you have to pick one, as D is either/or (
struct
vs.class
distinction). - Multiple inheritance: nope (actually, MI is OK if it’s interfaces)
- C++ templates: oh dear. D treats this purely as a linking problem: replicate the templated declarations D-side (D templates are a superset of C++ templates), replicate the symbol’s mangled name, then link against existing code. Existing code doesn’t exist on the C++ side? What are you trying to call, then?
- Linking against STL-using code is the goal. Proof-of-concept: successfully links against a call using
std::vector<T>
. It’s… a little scary, but it works. - Unsolved problem:
const
. This is becauseconst
in D is transitive, and it causes type names to mangle differently. - Unsolved problem: catching exceptions. Possible solution is to restrict to just the exception heirarchy used by STL. Audience comment: “People who throw
int
s deserve what they get.” - Project to build a C++ -> D interface generator using Clang exists.
Personal thoughts for Rust:
- This could be a killer feature for D. As far as I know, no language (which doesn’t just translate to C++) supports C++ interfacing in any non-insane manner. It would significantly reduce the barrier to incrementally replacing C++ with D code. I believe that if Rust wants to compete in this space, matching D’s capabilities here would be of considerable value.
- Rust is not as well-off as D in some areas: D has the advantage of its template system actually being a superset of C++'s. It also has conventional OO features. Finally, it has a several-year head start.
- Rust has two advantages I can think of: it doesn’t have the
struct
/class
split that D does, and it has non-transitive*mut
and*const
(at least, I don’t think they’re transitive in Rust). - This isn’t a question of all-or-nothing. Clearly, interfacing with any possible C++ code is just complete lunacy. D has thus far demonstrated that there’s a decently-sized proportion of C++ code that can be bound to without needing to integrate a full C++ compiler.
- With the Servo team looking to start adding components written in Rust into Firefox, might be an excellent opportunity to look at exactly what features would be most useful.
Video index:
- 00:30: C is the Lingua Franca.
- 01:00: C Interop is trivial.
- 01:55: C++ Interop? (HAHAHAHA).
- 03:00: Problems with the above: name mangling, templates, SFINAE, namespaces, overloading, argument-dependent lookup…
- 04:05: …overloading (again), virtual functions, exceptions, koenig lookup, operator overloading,
const
. - 04:40: You’d have to build a whole C++ front end into the language.
- 05:10: Or maybe not…
- 05:20: You don’t have to compile C++, just have to link to it.
- 06:05: D doesn’t have an analog of everything C++ has, so if we can be a bit plastic on both sides…
- 06:30: Example:
extern "C++" unsigned foo(char*& p);
- 06:55: D/C++ basic type “equivalences” (
sizeof long
LOL). - 09:05: What about:
extern "C++" void foo(long x);
? (name mangling hates you). - 10:10: D’s solution to
long
(struct wrapper with forwarding alias + evil compiler mangling magic). - 13:30 ish: how D deals with no standard C++ ABI/name mangling (lots of compiler-specific tables and reverse engineering and madness).
- 15:25: Unsolved problem:
const
(D’sconst
is transitive, C++'s isn’t). - 16:55: Struct layout matches C++ (already doing the same thing as C).
- 18:15: Struct member functions: the same.
- 18:25: Polymorphism (virtual functions) (object and vtable layouts different).
- 20:05: D supports COM interfaces (just inherit from magic
IUnknown
). - 21:40:
extern (C++) class C { ... }
in D. - 22:05: Multiple Inheritance (run away screaming).
- 22:40: Value or reference type? (structs/classes are different in D, but not in C++; pick one, can’t be both).
- 24:15: C++ Namespaces.
- 25:10: D name spaces.
- 25:35: Extend C++ Declaration (add namespace as
extern (C++, N.M) { void foo(); }
). - 26:45: C++ Templates: sfinae, partial ordering, dependent lookup, point of instantiation, primary template, template templates.
- 27:25: (Psychotic screaming)
- 27:55: Ignore All That: it’s just a name mangling problem. (D templates are a superset of C++ templates, so just fix mangling).
- 28:25: Example. (Note: need an instantiation on the C++ side to link against).
- 29:30: Template functions, too (with example and a doggie!).
- 30:25: Now It’s Time To Justify My Existence!
- 31:10: Interface to STL! (
std::vector<T>
) - 32:05: Example code.
- 32:45: D-side code:
vector
. - 34:30: More D:
allocator
(so effort, much oww, such proof of concept, many works). - 37:00: Question: what about function objects, algorithms, etc.? “Probably can be done.”
- 37:50: Question: if STL updates, do you have to update? “Yes. FML.”
- 38:10: Question: can you explain the various parts of the example implemenation? (Does so).
- 40:35: Question: (inaudible) “Why bother with [
allocator
] the D side? Because of the default argument and mangling.” - 42:25: Question: (inaudible) “If there’s no object code on the C++ code, you can’t link against it (RE: macros I think)”.
- 43:45: Question: (inaudible) “Yeah, it does!” (think it’s about mangling template default arguments).
- 45:35: Biggest remaining problem: catching C++ exceptions (C++ throws by value, D throws by reference; no idea how to solve that).
- 47:55: TLDR, no, wait, Question: (inaudible) “Andrei says we have to support exceptions. okay.jpg”.
- 50:00: Question: is the problem just that you can’t catch exceptions that the C++ code throws but doesn’t catch? “D -> C++ -> D -> C++ throws; what happens? How does it work? You can’t explain that!”
- 51:15: Question: (inaudible) “Don’t know yet.”
- 51:25: Question: if you restricted exceptions to subclasses of
exception
, would that make it easier? “Yes.” Would that be sufficient? “Don’t know yet.” People who throwint
s deserve what they get. (Restricting to STL’s exceptions might be sufficient and doable.) - 52:50: Question: (inaudble, something about exceptions unwinding through different contexts) “Question is, who gets
main
?” (something about C <-> C++) “Doable, but you have to be careful due to GC.” - 55:10: TL… Question: (inaudible) “What I’ve shown works.” (more) “Because we keep hearing ‘I want to use D, but I’m trapped by my C++ code!’.” (presumably asking about motivation for this) “Having a C interface isn’t good enough.”
- 57:00: Someone working on “Calypso” which is based on Clang that will output a D interface for C++ code.
- 58:10: Question: (inaudbile) “Yes. If you’re interfacing with C++, those templates must have been instantiated on the C++ side.” (hands waving) “Yes, no…” (gist: that code relies on having a
vector<float>
ctor on the C++ side; if you don’t need the C++ bits, just write it in D. Perhaps asking about using STL containers in D without C++ code). - 60:00: Question: templates on C++ side that bind to D templates? “C++ code that’s sufficiently D-like (i.e. the DMD compiler) can be translated to C++.”.
- 62:05: Question: (inaudible) “Well, who cares about
iostream
s?” - 63:00: Question: (inaudible) “D doesn’t support multiple inheritance, unless they’re interfaces.”
- 63:45: Question: (inaudible, IO streams) “Didn’t like it then, don’t like it now.”
- 64:30: Question: (inaudible) “There are multiple vtables for SI with interfaces. … It works with those, and the layout matches.”
- 66:45: Comment: I use some multiple inheritance in C++, but all but one has no data. … Even in IO streams, it’s really only multiple inheritance of interfaces. “I’m not doing it.”
- 67:55: Comment: (inaudible, about MI/interfaces) “It’s [MI] kind of an obsolete issue.”
- 69:15: Question: (inaudible) “How do you debug a mixed D/C++ program? … Visual Studio just thinks the D code is C++ code, so you can debug it. Same with GDB, except it now has some debug support for D constructs.”
- 71:10: Question: (inaudible) “Link-time optimisations. Unpopular: that’s the wrong way to build a compiler/linker system. Weds the two together. Unreasonable, unless Microsoft writes a D compiler. … Right way to do it: hand compiler all the source to your program, not one-file-at-a-time like C++. More practical and easier.”
- 74:05: Question: (inaudible, something about compilation speed of D c.f. C++) “… when I designed D, I avoided things that make C++ slow to compile. It’s much faster. If you still run out of memory, you can hand the compiler a subset of source files.”
- 76:05: TLDR: Can get pretty far, need to be flexible on both ends, interfaces to STL are not portable, requires non-trivial expertise.
- 76:10: It’ll never be 100%, but it’s tractible, infinitely better than C wrappers, no longer locked into existing C++ code.
- 76:15: Question: (inaudible) “It’s [D development] all volunteer work.”
- 77:40: Question: do you expect a standard ABI for C++ any time soon? “I have no idea. I don’t care about it. The ABI is the C++ compiler you’re trying to be compatible with.”
- 78:35: Question: what VCS do you use? “Git and GitHub.”
- 81:20: The End.