Re: exern (C) linkage problem

2010-07-20 Thread Lars T. Kyllingstad
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

2010-07-20 Thread bearophile
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

2010-07-20 Thread Lars T. Kyllingstad
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?

2010-07-20 Thread awishformore
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?

2010-07-20 Thread 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


Re: Why are string literals zero-terminated?

2010-07-20 Thread awishformore

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?

2010-07-20 Thread Trass3r

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

2010-07-20 Thread Ali Çehreli

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?

2010-07-20 Thread Mario Kroeplin
 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

2010-07-20 Thread torhu

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

2010-07-20 Thread Mike Linford
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

2010-07-20 Thread Jonathan M Davis
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

2010-07-20 Thread div0

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

2010-07-20 Thread Trass3r

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

2010-07-20 Thread Jonathan M Davis
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

2010-07-20 Thread bearophile
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

2010-07-20 Thread torhu

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.