tags:

views:

104

answers:

2

I'm converting the header files of a C library to D modules, and was wondering how I should handle C strings.

Using DMD 1, this works:

void f(char* s);  // Definition for C library's function.

But using DMD 2 (which I personally use, but I would like the modules to work for both) strings are const, so to get the same code using the modules to work requires

void f(const(char)* s);  // Definition for C library's function.

What should I do? Just use char* and make the 'client' code make the strings mutable somehow? Or modify the type depending on the version of the compiler compiling the code? If the former, what's the best way to make them mutable? I thought .dup would do it, but the compiler wasn't having a bar of it. If the latter, how would I go about doing it? I tried this:

version (D_Version2) {
    alias const(char)* charptr;
} else {
    alias char* charptr;
}

void f(charptr s);

But alas, the DMD 2 version isn't valid code for DMD 1, and all code in version blocks must be valid code for the compiler compiling the code, even if the code wouldn't be included in the resulting executable. So currently the code compiles in both, but you have to modify the alias first which, as you can imagine, isn't ideal.

+5  A: 

Hi,

You can use the mixin construct to use language-version-specific code that isn't valid in all versions. Example:

static if(version_major<2)
{
 alias char* charptr;
}
else
{
 mixin("alias const(char)* charptr;");
}

Regarding your actual question, I would suggest doing the same as when interfacing C libraries with C++ - define a type that's const(char)* for D2 and char* for D1, but only use it when appropriate (for example, if a function takes a char* for a buffer to write to, it probably wouldn't be appropriate to name const(char)* something as generic as "charptr"). LPCSTR could work ;)

I didn't understand the "What's the best way to make them mutable" question.

CyberShadow
Hello again. I ought to be paying you :]. The mixin trick doesn't work; `Error: identifier 'charptr' is not defined`. That makes sense; I don't think there are actually any functions that use a buffer, but I'll keep it in mind. re `LPCSTR`: My unix sensibilities would be too offended by this, I think. `cstring`?
Bernard
The code snippet works for me. Did you `import std.compiler` (the module where `version_major` is declared)?
CyberShadow
I did now; same result. v2.0.31
Bernard
Actually, it doesn't even work for DMD 1. If I use `version(D_Version2) { mixin() } else { alias }` DMD 1 works, but DMD 2 gets the same results.
Bernard
Nevermind, I am a moron (importing modules ABOVE the definition :o).
Bernard
A: 

Don't use mixins for this, it's the wrong tool for the job. What you really need is the 'version' statement, you can read about it in the Conditional Compilation page here: http://www.digitalmars.com/d/2.0/version.html

It won't compile / look at code that is for a different version. This allows to build different code for different D versions, or different OS's, different whatever.

Mixins probably works, but it's a heavy tool, doesn't have highlighted code (inside the quotes) and is just overly complicating things. The version statement is perfectly suited for this problem.

Daevius
"It won't compile / look at code that is for a different version." Absolutely incorrect. The `version` statement is an AST node, and therefore is parsed before any consideration is given to removing it. Changes in the language have made code that is valid D2 not parse as D1, and you cannot put code that won't parse inside of a `version` statement. You are thinking that the `version` statement acts like the C preprocessor (invalid define blocks aren't even _lexed_), and this is not the case with the `version` statement.
Bernard
Hm you seem to be right. I tested it with the following code which gives no error when comments are removed://version (ABCDE)//{ int a = [5, 4];//}It looks like it should be somewhat correct then.This is weird, as there might always be code only compilable for certain version. But still, using mixins is the wrong tool, be it we don't have a better tool :O, and I thought D was perfect...:P
Daevius
Your code up there _parses_ just fine: it's a type, an identifier, and an array literal initialiser. That's parsed into an AST node just fine. It's not until the compiler runs a semantic pass and sees that the types don't match that it errors out. | I feel that the `version` statement should be considered earlier in the compilation process to be of actual utility.
Bernard