On Saturday, 16 December 2017 at 08:56:59 UTC, SimonN wrote:
Hi,

I'm calling a C library through a D wrapper. The situation is like this:

C library has:
    struct A      { ... };
    A* create_a() { ... }
    void foo(A*)  { ... }

D wrapper declares:
    extern (C) {
        struct A {}
        A* create_a();
        void foo(A*);
    }

Just a nitpick, because sometimes the distinction matters: that's a binding, not a wrapper.



The memory of the A is allocated by the C library. All the D code ever sees is a pointer, an opaque handle to the resource. How will the compiler optimizations behave around this:

Question 1. Is that cast still safe in usercode if foo(a) changes some internal values in *a that are undetectable through the C API?

Not sure what you mean by "safe" in this context, but the mandate of const in D is that data will not change through that particular reference. It says nothing about what happens through other references to the same data, whether they be in D or C. If it's important to you that no data in an instance of A changes, then you'll have to audit the C functions to make sure they aren't changing anything. If it's not important, i.e. you only want to prevent changes on the D side and don't care if they happen on the C side, then that's fine.


Question 2. If yes, can the wrapper sanely declare foo(const A*) instead of foo(A*)?

In D, const function parameters serve as a bridge between mutable and immutable variables -- this particular implementation would accept A*, const A*, and immutable A*. For most purposes, on a C function binding it's nothing more than an annotation. Where it matters is if you pass immutable variables to the function -- if the parameter is const even when the function modifies the variable, D will allow immutable to be passed and you're looking at unexpected behavior.

So I would say it's not a good idea in the general case. Only add const to parameters in C function declarations if the C API actually declares those parameters as const.


My use case: My const-heavy D usercode calls Allegro 5, a C game/multimedia library without any const in its API, through the D bindings DAllegro5. I'm considering to make a PR implementing question 2. Github issue: https://github.com/SiegeLord/DAllegro5/issues/42

I would expect SiegeLord to reject such a PR. I know I would if someone submitted one to any Derelict packages. I suggest making wrapper functions for your specific use case (hence my insistence on the distinction above), preferably combining mutliple function calls into one where it makes sense. Since you know if you're using immutable variables or not and when it's fine to cast away const, you can make the parameters to the wrapper functions const and cast it away inside.



Reply via email to