August 10, 2007
Kirk McDonald Wrote:

> C. Dunn wrote:
> > 4) Not enough help for converting between D strings and C char*. There must be conversion functions which work regardless of whether the D string is dynamic or not, and regardless of whether the C char* is null terminated.  I'm not sure what the answer is, but this has lead to a large number of runtime bugs for me as a novice.
> > 
> 
> The std.string module has the toStringz and toString functions.
> 
> The toString function simply returns a slice over the C string:
> 
> char[] toString(char* ptr) {
> 	return ptr[0 .. strlen(ptr)];
> }
> 
> The toStringz function simply appends a null character (\0) to the end
> of the D string:
> 
> char* toStringz(char[] str) {
> 	return (str ~ \0).ptr;
> }
> 
> These are very simple operations, and it is fairly easy to adapt them to whatever needs you have.
Well, maybe I could not find an obvious solution, but let's explain the problems I had with char[] and char*.

I have a DLL defining the following (extern) function:
      extern(Windows) void GetName(char* name)
I would just like to put the name of the DLL in the variable name. What I would do in C is something like:
     extern(Windows) void GetName(char* name)
     {
          name = "The DLL name";
     }
This just won't work in D... My solution for now is the following:
     extern(Windows) void GetName(char* name)
    {
        foreach(ic, c; "The DLL name\0")
             name[ic]=c;
    }
which is ugly, but do you have a better solution?

--Gilles
August 10, 2007
> I would just like to put the name of the DLL in the variable name. What I
> would do in C is something like:
>      extern(Windows) void GetName(char* name)
>      {
>           name = "The DLL name";
>      }
Not tested/compiled, but would something like

const char[] DLL_NAME = "The DLL name";
extern(Windows) void GetName(char* name)
{
    name = DLL_NAME.ptr;
}

work?

 - Paul
August 10, 2007
Paul Findlay Wrote:

> > I would just like to put the name of the DLL in the variable name. What I
> > would do in C is something like:
> > Â  Â  Â extern(Windows) void GetName(char* name)
> > Â  Â  Â {
> > Â  Â  Â  Â  Â  name = "The DLL name";
> > Â  Â  Â }
> Not tested/compiled, but would something like
> 
> const char[] DLL_NAME = "The DLL name";
> extern(Windows) void GetName(char* name)
> {
> Â  Â  name = DLL_NAME.ptr;
> }
> 
> work?
Unfortunately, no.
I tried:
const char[15] DLL_NAME="The DLL name";
extern(Windows) void GetName(char* name)
{
     name = DLL_NAME.ptr;
}
August 10, 2007
> Unfortunately, no.
> I tried:
> const char[15] DLL_NAME="The DLL name";
Hmm.. String literals are supposed to have an additional '\0' (assuming that
is the problem), so you could also try:
name = "The DLL Name".ptr

Sorry about this being the blind leading the blind..

 - Paul
August 10, 2007
Paul Findlay Wrote:

> > Unfortunately, no.
> > I tried:
> > const char[15] DLL_NAME="The DLL name";
> Hmm.. String literals are supposed to have an additional '\0' (assuming that
> is the problem), so you could also try:
> name = "The DLL Name".ptr
> 
> Sorry about this being the blind leading the blind..
I already tried this one! (doesn't work either)
(In fact I tried
const char[15] DLL_NAME="The DLL name\0"; )
> 
>  - Paul

August 10, 2007
is this working for you?

extern(Windows) void GetName(ref char* name)
{
   name = "just modified".ptr;
}

void main ()
{
   char* cpt = "initial value".ptr;
   GetName(cpt);
   printf("%s",cpt);
}

Gilles G. wrote:
> Kirk McDonald Wrote:
>
>   
>> C. Dunn wrote:
>>     
>>> 4) Not enough help for converting between D strings and C char*. There must be conversion functions which work regardless of whether
>>> the D string is dynamic or not, and regardless of whether the C char*
>>> is null terminated.  I'm not sure what the answer is, but this has
>>> lead to a large number of runtime bugs for me as a novice.
>>>
>>>       
>> The std.string module has the toStringz and toString functions.
>>
>> The toString function simply returns a slice over the C string:
>>
>> char[] toString(char* ptr) {
>> 	return ptr[0 .. strlen(ptr)];
>> }
>>
>> The toStringz function simply appends a null character (\0) to the end
>> of the D string:
>>
>> char* toStringz(char[] str) {
>> 	return (str ~ \0).ptr;
>> }
>>
>> These are very simple operations, and it is fairly easy to adapt
>> them to whatever needs you have.
>>     
> Well, maybe I could not find an obvious solution, but let's explain the problems I had with char[] and char*.
>
> I have a DLL defining the following (extern) function:
>       extern(Windows) void GetName(char* name)
> I would just like to put the name of the DLL in the variable name. What I would do in C is something like:
>      extern(Windows) void GetName(char* name)
>      {
>           name = "The DLL name";
>      }
> This just won't work in D... My solution for now is the following:
>      extern(Windows) void GetName(char* name)
>     {
>         foreach(ic, c; "The DLL name\0")
>              name[ic]=c;
>     }
> which is ugly, but do you have a better solution?
>
> --Gilles
>   
August 10, 2007
Umm can we review what you are tying to do.. because if its something like
this (C version)

#include <stdio.h>

void GetName(char *name)
{
        name = "The right one";
}

int main()
{
        char *name = "the original";
        GetName(name);
        printf("%s\n", name);
}

it will print: the original

If you want name to hold "the right one" it will need to be a pointer to a pointer:

#include <stdio.h>

void GetName(char **name)
{
        *name = "The right one";
}

int main()
{
        char *name = "the original";
        GetName(&name);
        printf("%s\n", name);
        // will print: The right one
}

Otherwise, I give up..
August 10, 2007
Reply to Gilles G.,

> Kirk McDonald Wrote:
> 
>> C. Dunn wrote:
>> 
>>> 4) Not enough help for converting between D strings and C char*.
>>> There must be conversion functions which work regardless of whether
>>> the D string is dynamic or not, and regardless of whether the C
>>> char* is null terminated.  I'm not sure what the answer is, but this
>>> has lead to a large number of runtime bugs for me as a novice.
>>> 
>> The std.string module has the toStringz and toString functions.
>> 
>> The toString function simply returns a slice over the C string:
>> 
>> char[] toString(char* ptr) {
>> return ptr[0 .. strlen(ptr)];
>> }
>> The toStringz function simply appends a null character (\0) to the
>> end of the D string:
>> 
>> char* toStringz(char[] str) {
>> return (str ~ \0).ptr;
>> }
>> These are very simple operations, and it is fairly easy to adapt them
>> to whatever needs you have.
>> 
> Well, maybe I could not find an obvious solution, but let's explain
> the problems I had with char[] and char*.
> 
> I have a DLL defining the following (extern) function:
> extern(Windows) void GetName(char* name)
> I would just like to put the name of the DLL in the variable name.
> What I would do in C is something like:
> extern(Windows) void GetName(char* name)
> {
> name = "The DLL name";
> }
> This just won't work in D... My solution for now is the following:
> extern(Windows) void GetName(char* name)
> {
> foreach(ic, c; "The DLL name\0")
> name[ic]=c;
> }
> which is ugly, but do you have a better solution?
> --Gilles
> 

if you are passing a buffer this should work

extern(Windows) GetName(char* buf) // should have length to
{
static const char[] n = "The DLL name\0";
buf[0..n.length]=n[];
}


August 10, 2007
Kirk McDonald Wrote:

> Structs and classes are very different beasts in D, even if they look the same. However, there are some important differences in their use which should clue you in:
> 
> Using 'new' on a class gives you a reference, using it on a struct gives you a pointer.
> 
> Structs are plain ol' data. Saying "SomeStruct s;" gives you an instance you can immediately behind using. You have to use 'new' to get a class instance.
> 
> Classes have inheritance and all those other object-oriented features, while structs do not.
> 
> What I am getting at is that whether something should be a class or a struct seems like an important design decision which shouldn't be expected to change after development is well underway. Also, code doesn't really look all that similar when it uses structs vs. classes.


When converting C++ to D, the choice of struct or class is not so obvious.  struct has performance advantages, and testing may be required to decide whether that advantage is significant in context.

I would like to typedef (or alias) like this:

struct S{}
class C{}

version(fast){
  alias C Foo;
}else{
  alias S* Foo;
}

The problem is that, since S lacks ctor/dtor, I have to rewrite my code substantially.

If you doubt the performance difference, try this:

static import std.stdio;
static import std.c.stdlib;

struct A{
  int x = 57;
  void set(int y){
    x = y;
  }
};

void foo(uint n){
  auto all = new A*[n];
  uint c = n;
  while(c--){
    all[c] = new A;
  }
  c = n;
  while(c--){
    assert(all[c].x == 57);
    all[c].set(c);
    assert(all[c].x == c);
  }
  c = n;
  while(c--){
    delete all[c];
  }
}

class B{
  int x = 57;
  void set(int y){
    x = y;
  }
};

void bar(uint n){
  auto all = new B[n];
  uint c = n;
  while(c--){
    all[c] = new B;
  }
  c = n;
  while(c--){
    assert(all[c].x == 57);
    all[c].set(c);
    assert(all[c].x == c);
  }
  c = n;
  while(c--){
    delete all[c];
  }
}

int main(char[][] args)
{
  uint n = 1;
  if (args.length>1){
    n = std.c.stdlib.atoi(args[1].ptr);
  }
  //foo(n);
  bar(n);
  std.stdio.writefln("Done ", n);
  return 0;
}


[Here, I do not need ctors, since I have initializers.]

Use either foo() or bar().  With normal compilation, I get a 10% slow-down for the class.  With "-O -inline -release", I get 10% to 20%, and it's not even consistent.  Sometimes 10% is important, especially for system-level tasks.  One could fear an even bigger hit, so the ability to do comparative testing is important.

Someone said that Walter is adding ctors to structs.  That would help.  But note that I cannot write generic code!  operator new() returns different things in different situations!! If I try to use an alias or a typedef to switch between A* (pointer to struct A) and B (ref to class B), I cannot call new on the alias:

version(A){
  alias A* Foo;
}else{
  alias B Foo;
}

Foo x = new Foo;

This does not work!!!!!!!!!!  Hopefully, you can now see the problem.  This is a big impediment in converting C++ code to D, and not just b/c of the runtime difference.  The natural thing is to convert C-style structs to D structs, using std.c.stdlib.malloc()/free().  Then, during refactoring, a person might say, "Hmmm.  Maybe it would be cool to use D classes instead."  But the "refactoring" is a huge pain in the arse because of this inconsistency.

When Foo is a struct, the syntax should be "new Foo*()", not "new Foo()".  That completely solves the problem, but breaks existing code.

Solution: "operator New" with a capital N.

It's important to recognize that D is just an OK language all by itself.  Its great potential comes from its close resemblance to C++, making the transistion possible.  Smooth code re-factoring is extemely important if you want C++ coders to adopt D.

August 10, 2007
Reply to C. Dunn,

> 
> struct S{}
> class C{}
> version(fast){
> alias C Foo;
> }else{
> alias S* Foo;
> }
> The problem is that, since S lacks ctor/dtor, I have to rewrite my
> code substantially.
> 

For ctor you could use a static method to wrap the new for both cases. Not vary clean but the performance hit should be the same for both sides.

For dtor, no such luck. Then again I have yet to ever use a dtor in D.