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

> 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: