DIP87

From D Wiki
Jump to: navigation, search
Title: Enhanced foreign-language binding
DIP: 87
Version: 1
Status: Draft
Created: 2016-01-21
Last Modified: 2018-03-4
Author: Anon
Links:

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:

  • pragma(mangle, "foo")
    
    Changes only the symbol mangling, not the calling convention. Mostly useful for binding C symbols that share a name with a D keyword.
  • extern(LinkageType)
    
    Changes mangling and calling convention, but does not support binding to a name that is a D keyword.
  • @selector("foo")
    

    For Objective-C support. Does most of what this proposal aims to do, but is custom built for Objective-C, instead of being a multi-purpose tool.

  • extern(C++, ns)
    
    Supports mangling C++ symbols in namespaces. Also introduces the namespaces as symbols, which is not well loved by the community. Cannot bind symbols that share a name with a D keyword.

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 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 extern().
    4. A symbol inside an 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 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.

Copyright

This document has been placed in the Public Domain.