Re: exern (C) linkage problem
On Mon, 19 Jul 2010 18:01:25 -0400, bearophile wrote: typedef char* Cstring; extern(C) Cstring strcmp(Cstring s1, Cstring s2); ... You can use just a struct too: import std.string: toStringz; struct Cstring { const(char)* ptr; } extern(C) Cstring strcmp(Cstring s1, Cstring s2); Cstring toCString(T)(T[] s) { return Cstring(toStringz(s)); } void main() { auto s1 = abba; auto s2 = red; // auto r = strcmp(toCString(s1), s2); // compile error auto r = strcmp(toCString(s1), toCString(s2)); // OK } Bye, bearophile Good point. Actually, I think there should be a CString type in Phobos, but I think it should wrap a ubyte*, not a char*. The reason for this is that D's char is supposed to be a UTF-8 code unit, whereas C's char can be anything. -Lars
Re: exern (C) linkage problem
In that code, for further safety, I'd like to make it not possible (without a cast) code like this (here toStringz doesn't get called): strcmp(Cstring(s1.ptr), Cstring(s2.ptr)); So I think this code is a bit better: import std.string: toStringz; struct Cstring { const(char)* ptr; // const(ubyte)* ? static Cstring opCall(string s) { Cstring cs; cs.ptr = toStringz(s); return cs; } } extern(C) Cstring strcmp(Cstring s1, Cstring s2); void main() { auto s1 = abba; auto s2 = red; auto r2 = strcmp(Cstring(s1), Cstring(s2)); } Lars T. Kyllingstad: but I think it should wrap a ubyte*, not a char*. The reason for this is that D's char is supposed to be a UTF-8 code unit, whereas C's char can be anything. Right. But toStringz() returns a const(char)*, so do you want to change toStringz() first? Bye, bearophile
Re: exern (C) linkage problem
On Tue, 20 Jul 2010 05:10:47 -0400, bearophile wrote: In that code, for further safety, I'd like to make it not possible (without a cast) code like this (here toStringz doesn't get called): strcmp(Cstring(s1.ptr), Cstring(s2.ptr)); So I think this code is a bit better: import std.string: toStringz; struct Cstring { const(char)* ptr; // const(ubyte)* ? static Cstring opCall(string s) { Cstring cs; cs.ptr = toStringz(s); return cs; } } extern(C) Cstring strcmp(Cstring s1, Cstring s2); void main() { auto s1 = abba; auto s2 = red; auto r2 = strcmp(Cstring(s1), Cstring(s2)); } Lars T. Kyllingstad: but I think it should wrap a ubyte*, not a char*. The reason for this is that D's char is supposed to be a UTF-8 code unit, whereas C's char can be anything. Right. But toStringz() returns a const(char)*, so do you want to change toStringz() first? Yes. I think we should stop using char* when interfacing with C code altogether. The right thing to do, if you can call it that, would be to use char* only if you KNOW the C function expects text input encoded as UTF-8 (or just plain ASCII), and ubyte* for other encodings and non- textual data. But this rule requires knowledge of what each function does with its input and must hence be applied on a case-by-case basis, which makes automated translation of C headers to D difficult. So I say make it simple, don't assume that your C functions handle UTF-8, and use ubyte* everywhere. (Actually, it's not that simple, either. I just remembered that C's char is sometimes signed, sometimes unsigned...) Maybe this should be discussed on the main NG. It's been bothering me for a while. I think I'll start a topic on it later. -Lars
Why are string literals zero-terminated?
Following this discussion on announce, I was wondering why string literals are zero-terminated. Or to re-formulate, why only string literals are zero-terminated. Why that inconsistency? What's the rationale behind it? Does anyone know? /Max Did you test with a string that was not in the code itself, e.g. from a config file? String literals are null terminated so you wouldn't have had an issue if all your strings were literals. Utf8 doesn't contain the string length, so you will run in to problems eventually. You have to use toStringz or your own null terminator. Unless of course you know that the function will always be taking string literals. But even then leaving something like that up to the programmer to remember is not exactly fool proof. Enjoy. ~Rory Hey again and thanks for the hint. I tried finding something on the DM page about string literals being null terminated and while the section about string literals didn't even mention it, it was said some place else. That explains why using string literals works even though I expected it to fail. It's indeed good to know and adding std.string.toStringz is probably a good idea ;). Thanks. Greetings, Max. sure, I must admit it is annoying when the same code can do different things just because of where the data came from. It would be easier to notice the bug if d never added a null on literals, but then there would also be a lot more usages of toStringz. I think if you want to test it you can do: auto s = blah; open(s[0..$].dup.ptr); // duplicating it should put it somewhere else // just slicing will not test When thinking about it, it makes sense to have string literals null terminated in order to have C functions work with them. However, I wonder about some stuff, for instance: string s = string; // is s == string\0 now? char[] c = cast(char[])s; // is c[6] == '\0' now? char* p = s.ptr; // is *(p+6) == '\0' now? I think use of the zero terminator should be consistent. Either make every string (and char[] for that matter) zero terminated in the underlying memory for backwards compatibility with C or leave it to the user in all cases. /Max perhaps the NULL is there because its there in the executable file? NULL is also often after a dynamic array simply because of d always initializing memory, and when you get an allocation often a larger amount is allocated which remains NULL.
Re: Why are string literals zero-terminated?
On Tue, 20 Jul 2010 13:26:56 +, Lars T. Kyllingstad wrote: On Tue, 20 Jul 2010 14:59:18 +0200, awishformore wrote: Following this discussion on announce, I was wondering why string literals are zero-terminated. Or to re-formulate, why only string literals are zero-terminated. Why that inconsistency? What's the rationale behind it? Does anyone know? So you can pass them to C functions. Note that even though string literals are zero terminated, the actual string (the array, that is) doesn't contain the zero character. It's located at the memory position immediately following the string. string s = hello; assert (s[$-1] != '\0'); // Last character of s is 'o', not '\0' assert (s.ptr[s.length] == '\0'); Why is it only so for literals? That is because the compiler can only guarantee the zero-termination of string literals. The memory following a string in general could contain anything. string s = getStringFromSomewhere(); // I have no idea where s is coming from, so I don't // know whether it is zero-terminated or not. Better // make sure. someCFunction(toStringz(s)); -Lars
Re: Why are string literals zero-terminated?
Am 20.07.2010 15:38, schrieb Lars T. Kyllingstad: On Tue, 20 Jul 2010 13:26:56 +, Lars T. Kyllingstad wrote: On Tue, 20 Jul 2010 14:59:18 +0200, awishformore wrote: Following this discussion on announce, I was wondering why string literals are zero-terminated. Or to re-formulate, why only string literals are zero-terminated. Why that inconsistency? What's the rationale behind it? Does anyone know? So you can pass them to C functions. Note that even though string literals are zero terminated, the actual string (the array, that is) doesn't contain the zero character. It's located at the memory position immediately following the string. string s = hello; assert (s[$-1] != '\0'); // Last character of s is 'o', not '\0' assert (s.ptr[s.length] == '\0'); Why is it only so for literals? That is because the compiler can only guarantee the zero-termination of string literals. The memory following a string in general could contain anything. string s = getStringFromSomewhere(); // I have no idea where s is coming from, so I don't // know whether it is zero-terminated or not. Better // make sure. someCFunction(toStringz(s)); -Lars Hey. Yes, that indeed makes a lot of sense. I didn't actually try those asserts because I'm currently not on a dev machine, but what you point out basically is the behaviour I was hoping for. Thanks for clearing this up. /Max
monitor condition variables?
So synchronized implements mutual exclusion. http://www.digitalmars.com/d/2.0/class.html#synchronized-functions What about condition variables: http://en.wikipedia.org/wiki/Monitor_(synchronization)#Waiting_and_signaling Is there any standard way to do that?
Extending the lifetime of scope objects
What are all the cases that extend the lifetime of scoped objects? Binding a delegate to a scope object extends the lifetime of that object, which would normally end upon exiting that scope. The lifetime of i is extended here: int delegate(int) make_delegate() { int i;// lives as long as the returned delegate lives return (int param) { return i + param; // uses i }; } void main() { auto del = make_delegate(); del(42); // uses i } I was surprised to discover that, the same does not apply to struct objects, *if* the struct has a destructor: struct S { int i; ~this() // prevents life extension {} } int delegate(int) make_delegate() { auto s = S(); return (int param) { return s.i + param; }; } void main() { auto del = make_delegate(); del(42); } Error: variable deneme.make_delegate.s has scoped destruction, cannot build closure Are the life extending cases short and simple? What are they? :) Thank you, Ali
Re: associative arrays: to sort or not to sort?
Unless JSON requiers that the keys be in some order, No, JSON does not require the names of an object to be in alphabetical order. the correct solution is to make the check order independent. For example: string s = CallReturningJSON(); s = replace(s,`a:23.54`, `X`); s = replace(s,`b:0.0012`, `X`); s = replace(s,`{nested:{X,X}}`, `X`); s = replace(s,`goodbye:[true,or,false,[test,42,X]]`, `X`); s = replace(s,`array:[12,null,{}]`, `Y`); s = replace(s,is\n\ngreat, `Z`); s = replace(s,`json:Z`, `Y`); s = replace(s,`hello:{Y,Y}`, `X`); assert(s == `{X,X}`);. But this is lengthy and seems to lack additional assert checks. One way out could be to avoid real-world examples in the unittest. For the simple example of std.json that is only broken in theory, the correct solution could be: assert(s == `{a:1,b:null}` || s == `{b:null,a:1}`) But now assume, I want to implement a JSON-RPC encoder that uses std.json. A JSON-RPC request object has up to four name/value pairs (jsonrpc, method, params, id). Instead of only 2!, I now have 4! (too many) possible orders to check in the unittest of the JSON-RPC encoder. The unspecified order of the foreach iteration does not only affect the unittest of std.json, but also leaks out to far away implementations using std.json. The same is true for std.xml: assert(s == `tag goodbye=1 hello=0/`); may pass today, but is broken in theory! You have to notice that XML attributes are stored in an associative array and that toString is implemented using foreach. Until then, broken unit tests pass... This is a problem, isn't it?
Re: Extending the lifetime of scope objects
On 20.07.2010 21:54, Ali Çehreli wrote: What are all the cases that extend the lifetime of scoped objects? Binding a delegate to a scope object extends the lifetime of that object, which would normally end upon exiting that scope. The lifetime of i is extended here: int delegate(int) make_delegate() { int i;// lives as long as the returned delegate lives return (int param) { return i + param; // uses i }; } void main() { auto del = make_delegate(); del(42); // uses i } I was surprised to discover that, the same does not apply to struct objects, *if* the struct has a destructor: struct S { int i; ~this() // prevents life extension {} } int delegate(int) make_delegate() { auto s = S(); return (int param) { return s.i + param; }; } void main() { auto del = make_delegate(); del(42); } Error: variable deneme.make_delegate.s has scoped destruction, cannot build closure Are the life extending cases short and simple? What are they? :) When a local variable in a function (or delegate) is part of a nested delegate's context, that variable is heap allocated. Which just means the GC will collect it sometime after the last reference is gone. In your first example, it's like you did int* i = new int; What is supposed to happen with your struct example doesn't seem to be documented, neither in the docs or TDPL. Could be just an accident that it doesn't work. Or it could be on purpose, but there's no way of knowing without asking Walter or Andrei. There's a slight chance taking a reference to the struct itself instead of just a member will work. I guess you just hit a marginal case here.
const(type) vs. const type
I'm playing with QtD, and I tried to override a QWidget's sizeHint() function, which is declared as const QSize sizeHint(). I tried to override it by declaring my function as override const(QSize) sizeHint () . I got a compiler error that it was not covariant with const QSize, and when I changed it to that it worked fine. I've skimmed through the documentation but don't understand what the difference is. Any help? -- Mike Linford
Re: const(type) vs. const type
On Tuesday, July 20, 2010 15:57:41 Mike Linford wrote: I'm playing with QtD, and I tried to override a QWidget's sizeHint() function, which is declared as const QSize sizeHint(). I tried to override it by declaring my function as override const(QSize) sizeHint () . I got a compiler error that it was not covariant with const QSize, and when I changed it to that it worked fine. I've skimmed through the documentation but don't understand what the difference is. Any help? IIRC, const QSize sizeHint() is synonymous with QSize sizeHint() const which means that the function is const. However, const(QSize) sizeHint() means that the QSize returned is const rather than the function. - Jonathan M Davis
Re: const(type) vs. const type
On 20/07/2010 23:57, Mike Linford wrote: I'm playing with QtD, and I tried to override a QWidget's sizeHint() function, which is declared as const QSize sizeHint(). I tried to override it by declaring my function as override const(QSize) sizeHint () . I got a compiler error that it was not covariant with const QSize, and when I changed it to that it worked fine. I've skimmed through the documentation but don't understand what the difference is. Any help? const QSize sizeHint() means the object on which you are calling the function has to be const and the returned QSize is mutable (I think, it might also be const as well, I don't use that format of method signature...), whilst const(QSize) sizeHint() means a mutable object which returns a const object. Const is allowed before after the method signature which is confusing and annoying. In c++ it would be: (assuming QSize is a D class) QSize sizeHint() const { return _sh; } vs const QSize sizeHint() { return _sh; } -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk
Re: const(type) vs. const type
I'm playing with QtD, and I tried to override a QWidget's sizeHint() function, which is declared as const QSize sizeHint(). I tried to override it by declaring my function as override const(QSize) sizeHint () . I got a compiler error that it was not covariant with const QSize, http://digitalmars.com/d/2.0/const3.html In that case it is a const member function which means it is not allowed to change any part of the object through the member function's this reference.
Re: const(type) vs. const type
On Tuesday, July 20, 2010 16:23:23 div0 wrote: Const is allowed before after the method signature which is confusing and annoying. TDPL had an explanation for that that IIRC made fair sense, but I'd have to look it up again since I don't remember exactly what it was. Certainly, at first glance, it's a poor design decision. I'll obviously have to look it up again to see why it wasn't as bad a decision as it seems at first glance. - Jonathan M Davis
Re: const(type) vs. const type
div0: Const is allowed before after the method signature which is confusing and annoying. We have asked Walter to improve this situation, and he has refused, saying that keeping all D attributes syntax uniform is better. See also: http://d.puremagic.com/issues/show_bug.cgi?id=4040 Bye, bearophile
Re: const(type) vs. const type
On 21.07.2010 00:57, Mike Linford wrote: I'm playing with QtD, and I tried to override a QWidget's sizeHint() function, which is declared as const QSize sizeHint(). I tried to override it by declaring my function as override const(QSize) sizeHint () . I got a compiler error that it was not covariant with const QSize, and when I changed it to that it worked fine. I've skimmed through the documentation but don't understand what the difference is. Any help? In the first case, it's the function itself that ends up being const, not its return value. It's like putting 'const' after the parameter list in C++.In the second case, only the return value is const.