Hacker News new | past | comments | ask | show | jobs | submit login

Sure, but Swift is just one of many modern and (less modern) high-level languages, it's not just about connecting Swift to other languages than C or C++. There's also D, Rust, Nim, Zig, Python, Java, C#, even Javascript (when calling WASM modules), etc... those would all benefit from a more modern (and standardized!) approach to language bindings (even if the target languages would only be C or C++, but why stop there).

Apart from that "grand idea" I think a more realistic real-world solution for the C++ => Swift situation is to simply wrap the C++ API into a C API first, and then create a Swift API on top of the C API, instead of trying to somehow translate the C++ API directly to Swift. E.g. every C++ library should come with an optional C-API to simplify language bindings, or even just compiling that library into a DLL.




If we focus just on the programming cases where C++ has been heavily used, you can narrow that list down to D, Rust, Nim, and Zig. Dynamic languages or those with a heavy runtime like Python, Java, C#, and JavaScript are substantially different use cases.

Among those remaining, Swift has substantially more corporate backing, what with Apple relying on it for their massively successful iOS platform and Google trying to use it for TensorFlow.

C wrapper for C++ APIs has long been standard practice, but adds a substantial maintenance burden to C++ library authors and does not address semantics in the host language, which is a major part of this proposal. The whole proposal is based around the idea of seamless Swift to C++ interoperability. C++ has a lot of higher-level concepts that potentially can translate to similar higher-level concepts in other languages; round-tripping through a C API loses all of that.

To be clear, I like your idea - it's a grand one, and potentially solves the N+M problem once and for all. The real stumbling block for it is the C++ ABI and sheer mass of existing C++ code.


> E.g. every C++ library should come with an optional C-API to simplify language bindings, or even just compiling that library into a DLL.

hard to do without incurring additional dynamic allocations though. e.g. how would you make, say, an API that wraps construction / doing stuff / destruction of something that'd look like this :

    namespace mylib { 
    struct node { 
      std::vector<node> children;
      std::optional<float> value;
    }; 
    }
in C you'd likely have to have something that looks like

    mylib_node* mylib_node_alloc(void);
    void mylib_node_free(mylib_node*);

    // and then... 
    float* mylib_node_value(mylib_node*); // this ? 
    float mylib_node_value(mylib_node*, int* ok); // or this ? 

    void mylib_node_set_value(mylib_node*, float value, int set); // then there's this ?
    void mylib_node_set_value(mylib_node*, float* value); // or this ?
    void mylib_node_unset_value(mylib_node*); // or maybe this ? 
and all this cannot really be done without a dynamic allocation (which hopefully looks terrible to everyone), unless you fancy doing ugly ugly ugly stuff like

    struct mylib_node { char storage[sizeof c++ struct that was computed manually)]; }; 
so anything that'd allow other languages to understand at least C++ vocabulary would be a great boon in terms of perf, etc


You can do something like

    // Or replace with something like a Strong Type; https://www.fluentcpp.com/2017/05/05/news-strong-types-are-free/
    using NodeHandle = int;

    struct OptFloat { float Value; bool bInitialized = false; }; 

    NodeHandle CreateNode(NodeHandle* Children, int NumChildren, OptFloat Value);
    void DestroyNode(NodeHandle ToDestroy);

    void SetValue(NodeHandle ToSet,  OptFloat  NewValue);

Aside from that, you do raise a good point. If you implemented your C api over your implementation of node, you would be in for a bad time as the owning std::vector<node> won't keep valid your pointers valid.. This isn't suposed to be ragging on your code, it's really to point out the pitfalls of manual APIs.

> struct mylib_node { char storage[sizeof c++ struct that was computed manually)]; };

You can do;

    // IN C api, fill this in manually
    #define mylib_storagsize = ?

    struct mylib_node {char storage[MYLIB_STORAGESIZE]; };
    // or;
    struct mylib_node {void* storage; }
    // in node.cpp - the underlying C++ abstraction;
    static_assert(sizeof(mylib::node) == MYLIB_STORAGESIZE);

It's only _slightly_ better..




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: