const (and in)
Consider there is C function:
unsigned int foo(const unsigned int a);
const will have no effect on generated code, as if code passes compilation with const, nothing would break if there weren’t const — so C compiler uses it at compile time as code contract specifier only.
Is there any effort writing uint foo(in uint a); or uint foo(const uint a); for calling this function in D? Could this help D compiler generate more efficient code for calling foo, or this will have no effect (at least for value type arguments)?
ref and out
There is C function
unsigned int bar(unsigned int *a);
Am I obliged to use pointer syntax uint bar(uint* a); while translating this to D, or can I write uint bar(ref uint a); (or uint bar(out uint a);, if I know that a is only for output, from documentation on bar)? Are there additional hidden mechanics under ref and out, or they are just plain pointers as they seem to? Will D generate “glue code” for initializing out parameter to it’s default value when call goes out of D scope?
Update1: I have written simple code to test how refs and outs are handled in arguments — they actually seem to be plain pointers at least for ints, but out is not reset to initial value when passed — C side can still read it’s value and modify it, so it effectively acts like ref. I am unsure, if I should expect GC-related issues when I use things in this way.
Update2: Using ref instead of pointers in function result also works expected way. const is still untested, and I don’t know how to check for it without need to disassemble my program.
in(which is the same asconst scope) does not exist in C, becausescopedoes not exist in C. Andoutandrefdon’t exist in C either. Don’t use them withextern(C)functions. The compiler should probably give an error if you use them as in the parameters ofextern(C)functions, but it doesn’t surprise me if it doesn’t. If it happens to work, you’re just “lucky.” It may stop working at any time. Howrefandoutare implemented are implementation details of the compiler. Generally, you should only ever use modifiers onextern(C)functions which actually exist in C. D’s compiler isn’t going to do any magic to make D stuff work on anextern(C)function. It expects anextern(C)function to be a C function with the capabilities that C has, not D.The only two exceptions that I’m aware of are
pureandnothrow, since they don’t affect calling conventions at all, just whether D will let you call them from certain functions. So, you can mark C functions aspureand/ornothrow. But you had better be sure that the function is actually pure if you mark it withpure(or you could get nasty bugs) – the same goes withnothrow. Technically, @safe, @trusted, and @system could be used as well, but C functions really should be left as the default – @system – since they’re C functions.And no, marking a parameter to a C function as
constis not likely to help any with optimizations. If the parameter is a value type, then theconstis pointless from the caller’s perspective. The argument will be copied regardless. It only matters with reference types. In the case ofextern(C), that would be limited to pointers and structs with pointers in them (be it directly or indirectly). There might be some optimizations there, but I wouldn’t bet on it – especially with dmd, which doesn’t generally optimize code as well as gdc and ldc. At best, what the compiler can do is determine that after that call, the variable passed in hasn’t changed, which might enable other optimizations within the caller, but it’s highly dependent on the caller and the compiler.What is of greater concern is whether the C parameter is actually
const. In general, you’re fine, but in C, it’s legal to cast awayconstand alter a variable, whereas in D, it’s not. Where this is primarily likely to be a concern is withimmutabledata (string literals being a prime example). You risk a segfault or worse if anything tries to actually mutate the data. In general, that shouldn’t be an issue with a C functions parameters which are marked asconst(though it could be upon occasion), but it definitely means that marking a parameter asconstwhen C doesn’t is almost certainly a bad idea. If you do that, you need to be sure that the variable’s value is never actually altered by the C function. Because if you mark it asconstand then the C function mutates it, you’re going to have bugs.So, to sum up, I’d say that in general, you should only ever mark
extern(C)functions with C modifiers, not D-specific ones, and you shouldn’t generally mark parameters asconstunless they’re marked that way in C. If you know what the C function is actuallypure, you can mark it aspure. If you know that it’s actuallynothrow, you can mark it withnothrow. And if you know that the parameter isn’t ever mutated by the C function, then you can mark it asconst. But you should be very conservative about that, otherwise you will cause nasty bugs in your code.And read these pages if you haven’t already:
http://dlang.org/interfaceToC.html
http://dlang.org/htomodule.html