Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Interfacing D To Legacy C++ Code

Interfacing D To Legacy C++ Code

Abstract
C++ programmers have developed a vast investment of existing code. Use of this code from
other languages is normally impractical. Walter shows how
this code can be accessible from the D programming language.

C is the lingua franca of the programming language industry. By presenting a C interface, most languages can connect with one another, and connect to a vast treasure house of C code. But C++ code is very hard to provide an interface too, and almost no languages even attempt it. I'd long ago decided that in order to provide a direct interface from D to C++ would require essentially adding the full semantics of a C++ compiler to D, and that would be impractical. But the idea persistently recurs, as there is a lot of interest in interfacing D to legacy C++ code.

It turns out that we actually can, with minor adjustments to D, directly interface to quite a bit of C++, especially if one is willing to be a bit flexible on both the C++ and D sides. This presentation goes through the principles on how this works, what works and what doesn't work, and how one can retain an investment in C++ code while migrating to D.

Bio
Walter Bright is the creator and first implementer of the D programming language and has implemented compilers for several other languages. He's an expert in all areas of compiler technology, including front ends, optimizers, code generation, interpreter engines and runtime libraries. Walter regularly writes articles about compilers and programming, is known for engaging and informative presentations, and provides training in compiler development techniques. Many are surprised to discover that Walter is also the creator of the wargame Empire, which is still popular today over 30 years after its debut.

Northwest C++ Users' Group

January 21, 2015
Tweet

More Decks by Northwest C++ Users' Group

Other Decks in Programming

Transcript

  1. C is the Lingua Franca • Most every language has

    some sort of interface with C • And, of course, the classic being C++ is built on top of C
  2. • Name mangling • Templates • SFINAE • Namespaces •

    Overloading • Argument Dependent Lookup
  3. • RTTI • Virtual functions • Exceptions • Special member

    functions • Operator overloading • Const Oh My!
  4. D doesn't have an analog of everything C++ has, so

    if we can be a bit plastic on both sides...
  5. extern (C++) { uint foo(ref char* p); } Should connect

    to: extern “C++” { unsigned foo(char*& p); }
  6. D C++ char char byte signed char ubyte unsigned char

    short short ushort unsigned short int int uint unsigned long long long ulong unsigned long long
  7. struct __c_long { this(int x) { lng = x; }

    int lng; alias lng this; }
  8. Struct Layout Matches C++ C++: struct s { unsigned a;

    char c; double d; }; D: struct s { uint a; char c; double d; } Static members too!
  9. Polymorphism (virtual functions) • D classes have virtual functions –

    But object layout is different – vtbl[] layout is different
  10. D Supports COM Interfaces import std.c.windows.com; interface IHello : IUnknown

    { extern (Windows) int Print(); } class CHello : ComObject, IHello { HRESULT Print() { MessageBoxA(null, “hello”, null, MB_OK); } }
  11. C++ Namespaces namespace N { namespace M { void foo();

    } } namespace N { // not closed void bar(); }
  12. C++ Templates • SFINAE • Partial ordering • Dependent lookup

    • Point of instantiation • Primary template • Template templates
  13. C++: template<class X, int C> struct Boo { X v[C];

    }; D: extern (C++) struct Boo(X, int C) { X[C] v; }
  14. Toto Too! C++: template<class T> T func(T t) { return

    t; } func(3); ??$func@H@@YAHH@Z D: extern(C++) T func(T)(T t) { return t; } func(3); ??$func@H@@YAHH@Z Wizard of Oz
  15. extern (C++, std) { class vector(T, A = allocator!T) {

    final void push_back(ref const T); } }
  16. extern (C++, std) { struct allocator(T) { alias size_type =

    size_t; void deallocate(T* p, size_type sz) { (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); } } } extern (C++, __gnu_cxx) { struct new_allocator(T) { alias size_type = size_t; void deallocator(T*, size_type); } }
  17. Biggest Remaining Problem • Catching C++ exceptions – which are

    by value – D exceptions are by reference
  18. Tl,Dr; • Can get pretty far • Need to be

    flexible on both ends • Interfaces to STL are not portable • and requires non-trivial expertise
  19. • It'll never be 100% • But it's tractable •

    And infinitely better than C wrappers • No longer locked in to existing C++ code