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.