Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Enhanced foreign-language binding

Version 1
Created 2016-01-21
StatusDraft
Last modified --
Author Anon

Abstract

This DIP proposes a unified foreign language binding and name mangling syntax, to extend/replace existing approaches.

Rationale

Currently, D has a mixed bag approach to binding symbols from other languages, each with their own functionality:

This proposal aims to replace all of these with a single, extendable, uniform syntax. This solves some of the current woes with binding C and C++, while opening up possibilities for adding additional language support in future without further breaking changes.

Description

  1. Deprecate {.D} pragma(mangle, "foo")

    ,

    @selector("foo")
    

    , and

    extern(C++, ns)
    
  2. Change LinkageAttribute in the grammar to:\ \ extern ( LinkageType [, StringLiteral ] ) \ \ Which has the following semantics:

    1. Functions will be called with appropriate calling convention.
    2. Symbols will be mangled according to the expectations of LinkageType
    3. The name sent to the mangler is the concatenation of all the string parameters given to {.D} extern()

      .

    4. A symbol inside an {.D} extern(LinkageType)

      block implicitly gains LinkageType, and it is an error have multiple

      extern()
      

      s on one symbol with different LinkageTypes

    5. The exact formatting of the string parameter is specific to each LinkageType, and should be sensible for the language being bound.
    6. A symbol inside a struct, class, or similar inherits the LinkageType of its parent, and appends any needed separator automatically.
  3. Add LinkageType {.D} auto

    , which infers LinkageType from containing blocks, and defaults to D if there are none.

Usage

// Still works
// Mangles as "foo"
extern(C) int foo();

// No more pragma(mangle)
// Mangles as "body"
extern(C, "body") int body_();

// cppMangle("foo")
extern(C++) int foo();

// cppMangle("ns::foo")
extern(C++, "ns::foo") int foo();

// NB: Mangles as if it didn't have a module, and is a breaking change.
// "_D3fooFZi"
extern(D) int foo();

// "_D4bodyFZi"
extern(D, "body") int body_();

// Namespace block, does *not* introduce any symbols on its own
extern(C++, "ns::")
{
    // No extern() directly on the symbol, so it appends its own name
    // cppMangle("ns::foo")
    int foo();

    // auto to infer LinkageType from previous extern()
    // cppMangle("ns::body")
    extern(auto, "body") int body_();

    // It is a good idea to not use auto on blocks
    extern(C++, "sub::")
    {
        // cppMangle("ns::sub::foo")
        int foo();
    }
}

// Maintains current behavior, does not add to the symbol's mangled name
extern(C++)
{
    // cppMangle("foo")
    int foo();
}

// Extend same behavior to other languages
extern(C, "SDL_")
{
    // "SDL_init"
    void init();
}

// Even D
extern(D, "std.ascii.")
{
    // std.ascii.isAlphaNum.mangleof
    bool isAlphaNum(dchar) pure nothrow @nogc @safe;
}

// Nested symbols (those inside other symbols) append any
// needed separator for the mangler automatically.
extern(C++, "Object")
interface Object_
{
    // cppMangleOf("Object::foo")
    int foo();
}

// NB: The Objective-C mangler must add missing parameters
//     the same way selector generation currently does.
extern(Objective-C)
class SomeClass
{
    // selector: "length"
    // mangle: "_i_SomeClass_length"
    int length();

    // selector: "moveTo_f:f:"
    // mangle: "_i_SomeClass_moveTo_f_f_"
    void moveTo(float x, float y);

    // selector: "myMoveTo:d:"
    // mangle: "_i_SomeClass_myMoveTo_d_"
    extern(auto, "myMoveTo:") void moveTo(double x, double y);
}

Backwards Compatibility

Code that currently uses

pragma(mangle)

,

extern(C++, ns)

,

extern(D)

, or

@selector

would need to be updated.

There no longer would be a way to get

extern(D)

’s currently functionality explicitly, which may be detrimental to some generic code. However, simply omitting

extern(D)

entirely gives the current behavior.

There no longer would be a way to change a symbol’s mangling without also changing its calling convention, but that might be a good thing.

Binding C++ namespaces would no longer introduce the namespace as a symbol, leaving scoping to D’s module system. Again, this is believed to be a good thing.

This document has been placed in the Public Domain.