www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Disallow arrays as pointers

reply bearophile <bearophileHUGS lycos.com> writes:
I have translated C code similar to:


something foo(int n) {
    int *array = malloc(n * sizeof(int));

    int i;
    for (...) {
        for (i = 0; i < n; i++, array++) {
            *array = ...;
            *array = ...;
        }
    ...
}


Into D2 code similar to:


something foo(int n) {
    auto array = new int[n];

    size_t index;
    foreach (...) {
        foreach (i; 0 .. n) {
            array[index] = ...;
            *array = ...;
            index++;
        }
    ...
}


Do you see the bug I have found during the debugging? 

I think the D2 compiler has to catch this bug:

*array = ...;

D arrays aren't pointers. Letting the compiler see them as pointers is
bug-prone, not tidy, and doesn't help D newbies understand how D represents its
arrays.


My bug report:
http://d.puremagic.com/issues/show_bug.cgi?id=3990


Some very good comments about this topic:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=135391

Bye,
bearophile
Oct 30 2011
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, October 30, 2011 17:29:36 bearophile wrote:
 I have translated C code similar to:
 
 
 something foo(int n) {
     int *array = malloc(n * sizeof(int));
 
     int i;
     for (...) {
         for (i = 0; i < n; i++, array++) {
             *array = ...;
             *array = ...;
         }
     ...
 }
 
 
 Into D2 code similar to:
 
 
 something foo(int n) {
     auto array = new int[n];
 
     size_t index;
     foreach (...) {
         foreach (i; 0 .. n) {
             array[index] = ...;
             *array = ...;
             index++;
         }
     ...
 }
 
 
 Do you see the bug I have found during the debugging?
 
 I think the D2 compiler has to catch this bug:
 
 *array = ...;
 
 D arrays aren't pointers. Letting the compiler see them as pointers is
 bug-prone, not tidy, and doesn't help D newbies understand how D represents
 its arrays.
 
 
 My bug report:
 http://d.puremagic.com/issues/show_bug.cgi?id=3990
 
 
 Some very good comments about this topic:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&ar
 ticle_id=135391
Arrays in D implicitly convert to their ptr property, so they essentially _are_ pointers in that sense. Now, personally, I think that it would be a good idea for them _not_ to implicitly convert, forcing you to explicitly use the ptr property, since you really shouldn't be treating arrays as pointers in D code. It's primarily when interacting with C code that you need to do that sort of thing, and the ptr property deals with it just fine. However, I don't think that you're going to find a general consensus that the implicit conversion is bad, and changing it now would likely break a lot of code. So, while I do think that it would be a good change, I really don't think that it's going to happen at this point. - Jonathan M Davis
Oct 30 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 However, I don't think that you're going to find a general consensus that the 
 implicit conversion is bad,
I'll keep count how many are against this idea.
 and changing it now would likely break a lot of code.
How much code is broken by this? It's bad D code that's easy to fix adding a ".ptr", or using "-d" (deprecated) to compile the code. So, while I do think that it would be a good change, I really don't
 think that it's going to happen at this point.
Let's break some code, to avoid even more bugs/breakage later! :-) (I am asking for some other little breaking changes in Bugzilla. This is not the only one.) Bye, bearophile
Oct 30 2011
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, October 30, 2011 18:10:06 bearophile wrote:
 Jonathan M Davis:
 However, I don't think that you're going to find a general consensus
 that the implicit conversion is bad,
I'll keep count how many are against this idea.
 and changing it now would likely break a lot of code.
How much code is broken by this? It's bad D code that's easy to fix adding a ".ptr", or using "-d" (deprecated) to compile the code.
I think that it will primarily affect strings (though in many such cases toStringz or toUTFz should generally be used), but from what I understand, it's quite common for D programmers interacting with C code to just pass arrays to C functions without using the ptr property. - Jonathan M Davis
Oct 30 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 from what I understand, 
 it's quite common for D programmers interacting with C code to just pass 
 arrays to C functions without using the ptr property.
That code works with an implicit conversion that saves the typing of 4 more chars, while introducing something that is negative for both newbie D programmers and more trained ones. ".ptr" was introduced in D to avoid this. In general I find it curious that D design tries to avoid some mistakes of the C design, and to disallow some bug-prone features of C, like some implicit type conversions. But then, it seems that D doesn't take a lot of care to avoid bug-prone "features" that it has introduced, that were not present in C (like the one discussed here, like lax management of strings that represent operators of operator overloading, etc.) Thank you for your answers, bye, bearophile
Oct 30 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/31/2011 12:03 AM, bearophile wrote:
 Jonathan M Davis:

 from what I understand,
 it's quite common for D programmers interacting with C code to just pass
 arrays to C functions without using the ptr property.
That code works with an implicit conversion that saves the typing of 4 more chars, while introducing something that is negative for both newbie D programmers and more trained ones. ".ptr" was introduced in D to avoid this. In general I find it curious that D design tries to avoid some mistakes of the C design, and to disallow some bug-prone features of C, like some implicit type conversions. But then, it seems that D doesn't take a lot of care to avoid bug-prone "features" that it has introduced, that were not present in C (like the one discussed here, like lax management of strings that represent operators of operator overloading, etc.)
I have never had a bug because of arrays implicitly converting to pointers. I'd sometimes even like e.g. ++array to mean array=array[1..$]. A lot of C's carefully designed syntactic elegance is lost when going from pointers/iterators to arrays and ranges. But why is *array not bounds checked in non-release mode? I think it should be. The lax management of strings is not a bug-prone feature. (in the sense that it would be likely to produce erroneous code because of subtle typing mistakes.) Sure, if the implementer of the aggregate using operator overloading does not handle invalid sequences, it can be "exploited" to gain access to private members and/or implementation details. That does not happen by accident. I don't think Phobos helps enough to make correct handling easy, maybe some simple isOpBinary(string), isOpUnary(string), etc. templates would be worth adding.
Oct 30 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 I have never had a bug because of arrays implicitly converting to 
 pointers.
Good.
 A lot of C's carefully designed syntactic elegance is 
 lost when going from pointers/iterators to arrays and ranges.
You see that D design tries hard to avoid the need to use pointers as much as possible, because pointers are bug prone, give less readable code, and they are not needed in most cases (you use something a bit higher level, like arrays or references). Some people say that C language is as elegant as a katana sword, but I have to say that most times you want to keep it in its sheath :-)
 But why is *array not bounds checked in non-release mode? I think it should be.
In D there are arrays, and there are pointers. Arrays are bound-checked, pointers aren't. So when you use arrays as pointers, or when you use somearray.ptr[x] you have lost array bounds. Adding a third intermediate type is not a good idea, it increases language and implementation complexity for a practice that is meant as discouraged since the introduction of the ptr field. Bye, bearophile
Oct 30 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 A lot of C's carefully designed syntactic elegance is 
 lost when going from pointers/iterators to arrays and ranges.
I think that a large part of that C syntactic elegance is an illusion. From my experience, I want my code to look very simple to read and clean every time this is possible. I want it to be easy to port to other languages, because I have do it often enough. C code that uses lot of pointers is often bug-prone, messy and hard to safely translate to other languages. There are situation where pointers are necessary or are better than the alternatives, or they give the needed flexibility, so I prefer a language with pointers, but in a well designed language those situations are not common, and I think raw pointers should be avoided when they are not needed. I have debugged enough C code to be rather sure of this. Good luck with your pointers. Bye, bearophile
Oct 30 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/31/2011 02:49 AM, bearophile wrote:
 Timon Gehr:

 A lot of C's carefully designed syntactic elegance is
 lost when going from pointers/iterators to arrays and ranges.
I think that a large part of that C syntactic elegance is an illusion. From my experience, I want my code to look very simple to read and clean every time this is possible. I want it to be easy to port to other languages, because I have do it often enough. C code that uses lot of pointers is often bug-prone, messy and hard to safely translate to other languages. There are situation where pointers are necessary or are better than the alternatives, or they give the needed flexibility, so I prefer a language with pointers, but in a well designed language those situations are not common, and I think raw pointers should be avoided when they are not needed. I have debugged enough C code to be rather sure of this. Good luck with your pointers.
I rarely use pointers in D, its arrays are a better concept. I just remarked that C code using pointers is sometimes more elegant than equivalent D code using arrays or ranges, and that it is a little bit unfortunate that we have all that while(*p && *p++ == --*q++){} stuff in the D grammar without the possibility to use it.
Oct 31 2011
parent deadalnix <deadalnix gmail.com> writes:
Le 31/10/2011 21:35, Timon Gehr a écrit :
 On 10/31/2011 02:49 AM, bearophile wrote:
 Timon Gehr:

 A lot of C's carefully designed syntactic elegance is
 lost when going from pointers/iterators to arrays and ranges.
I think that a large part of that C syntactic elegance is an illusion. From my experience, I want my code to look very simple to read and clean every time this is possible. I want it to be easy to port to other languages, because I have do it often enough. C code that uses lot of pointers is often bug-prone, messy and hard to safely translate to other languages. There are situation where pointers are necessary or are better than the alternatives, or they give the needed flexibility, so I prefer a language with pointers, but in a well designed language those situations are not common, and I think raw pointers should be avoided when they are not needed. I have debugged enough C code to be rather sure of this. Good luck with your pointers.
I rarely use pointers in D, its arrays are a better concept. I just remarked that C code using pointers is sometimes more elegant than equivalent D code using arrays or ranges, and that it is a little bit unfortunate that we have all that while(*p && *p++ == --*q++){} stuff in the D grammar without the possibility to use it.
Well you can do that in D. The thing is to not do it implicitely because it is a dangerous behaviour and you should go into this only if you know what you are doing and not by mistake.
Nov 02 2011
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 30/10/2011 22:46, Jonathan M Davis a écrit :
 On Sunday, October 30, 2011 17:29:36 bearophile wrote:
 Arrays in D implicitly convert to their ptr property, so they essentially
 _are_ pointers in that sense. Now, personally, I think that it would be a good
 idea for them _not_ to implicitly convert, forcing you to explicitly use the
 ptr property, since you really shouldn't be treating arrays as pointers in D
 code. It's primarily when interacting with C code that you need to do that
 sort of thing, and the ptr property deals with it just fine.
That cannot be more true.
Oct 31 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I didn't know that would compile.

Anyway, if one really wants to treat arrays like pointers he can do:
*array.ptr
Oct 30 2011
prev sibling next sibling parent Don <nospam nospam.com> writes:
On 30.10.2011 22:29, bearophile wrote:
 I have translated C code similar to:


 something foo(int n) {
      int *array = malloc(n * sizeof(int));

      int i;
      for (...) {
          for (i = 0; i<  n; i++, array++) {
              *array = ...;
              *array = ...;
          }
      ...
 }


 Into D2 code similar to:


 something foo(int n) {
      auto array = new int[n];
              *array = ...;
 I think the D2 compiler has to catch this bug:

 *array = ...;

 D arrays aren't pointers. Letting the compiler see them as pointers is
bug-prone, not tidy, and doesn't help D newbies understand how D represents its
arrays.
What's New for D 0.177 Dec 9, 2006 New/Changed Features Arrays no longer implicitly convert to pointers unless -d is used. For example, this code: void main() { int[] x = new int[59]; int *q = x; } compiled on 0.176 and earlier, but not any more. The case involving *arr seems to have just been missed. This is a simple accepts-invalid bug. Not an enhancement request.
Oct 31 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Kenji Hara (and the D community) is really good, he has already written a pull
request with the bug fix:
https://github.com/D-Programming-Language/dmd/pull/483

---------------------

Kenji Hara has fixed about 1/3 of the issue, so he asked me to split the but
report, this is a spin off:
http://d.puremagic.com/issues/show_bug.cgi?id=6869

In DMD 2.056 this code compiles:

void main() {
   int[] a1 = [5, 4, 3];
   int* p1 = cast(int*)a1; // no compile error here
}


Similar code using user-created struct doesn't compile:


struct Foo {
    int* p;
    size_t n;
}
void main() {
    Foo f;
    auto x = cast(int*)f; // compile error here
}


I don't see the need to accept this cast, because we have said that D arrays
are not pointers, and allowing the array to pointer cast means
introducing/leaving an useless special case, and in practice this special case
is not useful because arrays have the ptr property:


struct Foo {
    int* p;
    size_t n;
}
void main() {
    Foo f;
    auto x = f.ptr; // OK
}


So I think cast(int*)a1 should be forbidden.

-----------------------

The third part of the bug report was part of this older one:
http://d.puremagic.com/issues/show_bug.cgi?id=3971

The idea is to forbid code like:

void main() {
   int[3] a;
   a = 1;
   assert(a == [1, 1, 1]);
}


And require the square brackets every time an array operation is performed, for
syntactic uniformity with the other vector ops, and to avoid mistakes:


void main() {
   int[3] a;
   a[] = 1;
   assert(a == [1, 1, 1]);
}

Bye,
bearophile
Oct 31 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/31/2011 08:34 PM, bearophile wrote:
 Kenji Hara (and the D community) is really good, he has already written a pull
request with the bug fix:
 https://github.com/D-Programming-Language/dmd/pull/483

 ---------------------

 Kenji Hara has fixed about 1/3 of the issue, so he asked me to split the but
report, this is a spin off:
 http://d.puremagic.com/issues/show_bug.cgi?id=6869

 In DMD 2.056 this code compiles:

 void main() {
     int[] a1 = [5, 4, 3];
     int* p1 = cast(int*)a1; // no compile error here
 }


 Similar code using user-created struct doesn't compile:


 struct Foo {
      int* p;
      size_t n;
 }
 void main() {
      Foo f;
      auto x = cast(int*)f; // compile error here
 }
That is not similar code. This is: struct Foo { size_t length; int* ptr; T opCast(T: int*)(){return ptr;} } void main() { Foo f; auto x = cast(int*)f; // no compile error here }
 I don't see the need to accept this cast, because we have said that D arrays
are not pointers, and allowing the array to pointer cast means
introducing/leaving an useless special case, and in practice this special case
is not useful because arrays have the ptr property:
extern(C) void foo(char* str); foo(cast(char*)"hello");
 struct Foo {
      int* p;
      size_t n;
 }
 void main() {
      Foo f;
      auto x = f.ptr; // OK
 }
Actually compile error :o).
 So I think cast(int*)a1 should be forbidden.
-1. I don't really see any point in disallowing it. It is an explicit cast, not some kind of bug prone implicit behaviour.
 -----------------------

 The third part of the bug report was part of this older one:
 http://d.puremagic.com/issues/show_bug.cgi?id=3971

 The idea is to forbid code like:

 void main() {
     int[3] a;
     a = 1;
     assert(a == [1, 1, 1]);
 }


 And require the square brackets every time an array operation is performed,
for syntactic uniformity with the other vector ops, and to avoid mistakes:


 void main() {
     int[3] a;
     a[] = 1;
     assert(a == [1, 1, 1]);
 }
+1. That helps static type safety a bit and forces code to be more readable.
Oct 31 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Similar code using user-created struct doesn't compile:


 struct Foo {
      int* p;
      size_t n;
 }
 void main() {
      Foo f;
      auto x = cast(int*)f; // compile error here
 }
That is not similar code. This is: struct Foo { size_t length; int* ptr; T opCast(T: int*)(){return ptr;} } void main() { Foo f; auto x = cast(int*)f; // no compile error here }
I see. The bug report of mine asks to remove that opCast() then :-)
 extern(C) void foo(char* str);
 foo(cast(char*)"hello");
cast(char*) is D code, it's not a legacy C idiom, so you are writing it now in the D programs. Five years from now do you prefer D programmers to write: extern(C) void puts(const char* str); void main() { puts(cast(char*)"hello"); } Or: extern(C) void puts(const char* str); void main() { puts("hello".ptr); } ? Casts are unsafe and using the ptr is even shorter to write. I don't seen the need of that opCast.
 -1. I don't really see any point in disallowing it. It is an explicit 
 cast, not some kind of bug prone implicit behaviour.
In D there is only one syntax to perform a const cast or reinterpret cast, so D casts are sometimes dangerous: you change something but you forgot to update one cast, the compiler gives you zero warnings because casts are usually silently accepted, and your code breaks. This has happened to me more than one time in D coding. It's much better to minimize their number in the D code (and it's often better to write them in a smart way, with a type taken from what you are working on, like cast(typeof(x)), instead of specifying an explicit type like cast(int)). Sometimes I am not happy even using Unqual!(), I'd like something that performs a more focused job, like a Deconst!() that only removes all the const/immutable from a type, and nothing else. Bye, bearophile
Oct 31 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/01/2011 01:38 AM, bearophile wrote:
 Timon Gehr:
 extern(C) void foo(char* str);
 foo(cast(char*)"hello");
cast(char*) is D code, it's not a legacy C idiom, so you are writing it now in the D programs. Five years from now do you prefer D programmers to write: extern(C) void puts(const char* str); void main() { puts(cast(char*)"hello"); }
That works without the cast.
 Or:

 extern(C) void puts(const char* str);
 void main() {
      puts("hello".ptr);
 }
That works without the ".ptr".
 ?
 Casts are unsafe and using the ptr is even shorter to write. I don't seen the
need of that opCast.
I was casting to char*, not const(char*). It is just that occasionally C headers/bindings lack the const qualifier. Then passing a string literal is achieved simplest by a cast to char*. I don't think we really need that feature, I just think that removing it breaks existing code without a reason. extern(C) void puts(char* str); void main() { puts(cast(char*)"hello"); }
Nov 01 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
In the meantime Walter has added the patch to the latest DMD.

Timon Gehr:

 That works without the cast.
 That works without the ".ptr".
Right. There is an implict conversion between the 2-word struct of the string to the nude pointer.
 I was casting to char*, not const(char*). It is just that occasionally C 
 headers/bindings lack the const qualifier. Then passing a string literal 
 is achieved simplest by a cast to char*.
In some situations like that I think that using someString.dup.ptr looks safer, or better using toStringz: http://d-programming-language.org/cutting-edge/phobos/std_string.html#toStringz I'd like toStringz to be pure and return a char*, so its result is assignable to immutable despite being fit for C functions without const too. To do this, it can't contain a ~ (string concat) because currently the ~ is not a pure function, it always returns a string, dstring, wstring. So I think this should compile: char[] foo(string s1, string s2) pure { return s1 ~ s2; } void main() {} And regarding toStringz(), this modified version seems to work as desired: import core.stdc.string; char* toStringz(immutable(char[]) s) pure nothrow in { // The assert below contradicts the unittests! //assert(memchr(s.ptr, 0, s.length) == null, //text(s.length, ": `", s, "'")); } out (result) { if (result) { auto slen = s.length; while (slen > 0 && s[slen-1] == 0) --slen; assert(strlen(result) == slen); assert(memcmp(result, s.ptr, slen) == 0); // overkill? } } body { /+ Unfortunately, this isn't reliable. We could make this work if string literals are put in read-only memory and we test if s[] is pointing into that. /* Peek past end of s[], if it's 0, no conversion necessary. * Note that the compiler will put a 0 past the end of static * strings, and the storage allocator will put a 0 past the end * of newly allocated char[]'s. */ char* p = &s[0] + s.length; if (*p == 0) return s; +/ // Need to make a copy auto copy = new char[s.length + 1]; copy[0..s.length] = s; copy[s.length] = 0; return copy.ptr; } void main() { string t = "hello"; char* s1 = toStringz(t); const(char*) s2 = toStringz(t); immutable(char*) s3 = toStringz(t); immutable(char)* s4 = toStringz(t); }
 I don't think we really need that feature, I just think that removing it breaks
 existing code without a reason.
 
 extern(C) void puts(char* str);
 void main() {
       puts(cast(char*)"hello");
 }
I prefer something like: extern(C) void puts(char* str); void main() { puts(Deconst!("hello".ptr)); } This avoids a cast, a Deconst template doesn't change the data, it never forces the string to be of a specific char type. Thank you for your answers, bearophile
Nov 01 2011
parent bearophile <bearophileHUGS lycos.com> writes:
 So I think this should compile:
 
 char[] foo(string s1, string s2) pure {
     return s1 ~ s2;
 }
 void main() {}
The situation is a bit more complex: char[] foo(immutable string s1, immutable string s2) pure { return s1 ~ s2; } void main() { string t1 = "foo"; string t2 = "bar"; auto t3 = t1 ~ t2; static assert(is(typeof(t3) == string)); } So there I was asking for the druntime array concat to return something immutable that is implicitly cast-able to mutable. It's kind of the opposite of the recently introduced rule for strongly pure functions... So I don't know if this is possible.
 And regarding toStringz(), this modified version seems to work as desired:
http://d.puremagic.com/issues/show_bug.cgi?id=6878 Bye, bearophile
Nov 01 2011
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 31/10/2011 21:25, Timon Gehr a écrit :
 On 10/31/2011 08:34 PM, bearophile wrote:
 I don't see the need to accept this cast, because we have said that D
 arrays are not pointers, and allowing the array to pointer cast means
 introducing/leaving an useless special case, and in practice this
 special case is not useful because arrays have the ptr property:
extern(C) void foo(char* str); foo(cast(char*)"hello");
 struct Foo {
 int* p;
 size_t n;
 }
 void main() {
 Foo f;
 auto x = f.ptr; // OK
 }
Actually compile error :o).
 So I think cast(int*)a1 should be forbidden.
-1. I don't really see any point in disallowing it. It is an explicit cast, not some kind of bug prone implicit behaviour.
Well, because the ptr property is done for that. Actually, D ABI says that the struct representing the array begins with length, then prt, so the result isn't obvious from a low level perspective, which is kinda sad when it goes to pointer manipulation.
Nov 02 2011
parent Don <nospam nospam.com> writes:
On 02.11.2011 22:19, deadalnix wrote:
 Le 31/10/2011 21:25, Timon Gehr a écrit :
 On 10/31/2011 08:34 PM, bearophile wrote:
 I don't see the need to accept this cast, because we have said that D
 arrays are not pointers, and allowing the array to pointer cast means
 introducing/leaving an useless special case, and in practice this
 special case is not useful because arrays have the ptr property:
extern(C) void foo(char* str); foo(cast(char*)"hello");
 struct Foo {
 int* p;
 size_t n;
 }
 void main() {
 Foo f;
 auto x = f.ptr; // OK
 }
Actually compile error :o).
 So I think cast(int*)a1 should be forbidden.
-1. I don't really see any point in disallowing it. It is an explicit cast, not some kind of bug prone implicit behaviour.
Well, because the ptr property is done for that. Actually, D ABI says that the struct representing the array begins with length, then prt, so the result isn't obvious from a low level perspective, which is kinda sad when it goes to pointer manipulation.
The fix has already been implemented in git master. The bug report is closed. There's no point commenting on this topic further.
Nov 03 2011
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 31 October 2011 at 20:26:35 UTC, Timon Gehr wrote:
 On 10/31/2011 08:34 PM, bearophile wrote:
 Kenji Hara (and the D community) is really good, he has 
 already written a pull request with the bug fix:
 https://github.com/D-Programming-Language/dmd/pull/483

 ---------------------

 Kenji Hara has fixed about 1/3 of the issue, so he asked me to 
 split the but report, this is a spin off:
 http://d.puremagic.com/issues/show_bug.cgi?id=6869

 In DMD 2.056 this code compiles:

 void main() {
     int[] a1 = [5, 4, 3];
     int* p1 = cast(int*)a1; // no compile error here
 }


 Similar code using user-created struct doesn't compile:


 struct Foo {
      int* p;
      size_t n;
 }
 void main() {
      Foo f;
      auto x = cast(int*)f; // compile error here
 }
That is not similar code. This is: struct Foo { size_t length; int* ptr; T opCast(T: int*)(){return ptr;} } void main() { Foo f; auto x = cast(int*)f; // no compile error here }
 I don't see the need to accept this cast, because we have said 
 that D arrays are not pointers, and allowing the array to 
 pointer cast means introducing/leaving an useless special 
 case, and in practice this special case is not useful because 
 arrays have the ptr property:
extern(C) void foo(char* str); foo(cast(char*)"hello");
 struct Foo {
      int* p;
      size_t n;
 }
 void main() {
      Foo f;
      auto x = f.ptr; // OK
 }
Actually compile error :o).
 So I think cast(int*)a1 should be forbidden.
-1. I don't really see any point in disallowing it. It is an explicit cast, not some kind of bug prone implicit behaviour.
 -----------------------

 The third part of the bug report was part of this older one:
 http://d.puremagic.com/issues/show_bug.cgi?id=3971

 The idea is to forbid code like:

 void main() {
     int[3] a;
     a = 1;
     assert(a == [1, 1, 1]);
 }


 And require the square brackets every time an array operation 
 is performed, for syntactic uniformity with the other vector 
 ops, and to avoid mistakes:


 void main() {
     int[3] a;
     a[] = 1;
     assert(a == [1, 1, 1]);
 }
+1. That helps static type safety a bit and forces code to be more readable.
I saw that it was closed today: https://issues.dlang.org/show_bug.cgi?id=6869 Sorry for reviving an old thread. But I have to think that the problem will not be seen in newer versions? Thanks... SDB 79
May 13 2023
parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 13 May 2023 at 12:55:24 UTC, Salih Dincer wrote:
 I saw that it was closed today:

 https://issues.dlang.org/show_bug.cgi?id=6869
A new issue has been reported by Steven Schveighoffer: https://issues.dlang.org/show_bug.cgi?id=23919
 Casting an array to a pointer is allowed:
 
 ```d
 import core.stdc.stdio;
 auto str = "hello";
 printf(cast(char *)str[0 .. 3]);
 ```
 
 This prints "hello".
 
 The user might think they have properly matched the 
 requirements, but in
 actuality, all they have done is accessed the pointer.
 
 A few reasons why this is bad:
 
 1. It's trivial (and more readable) to use `.ptr` instead of 
 the cast
 2. The cast must match the attributes or risk causing problems 
 when code
 evolves. Casting is a blunt instrument, and should be 
 discouraged when
 better alternatives exist.
 3. The cast gives a false impression that something is 
 happening underneath
 to ensure the data is correct. Many C functions require 
 pointers instead of
 arrays, and this "seems" like the right answer.
 
 I think we should deprecate this "feature". I'm not exactly 
 sure why this
 was needed in the first place.
 

 opening this to
 hopefully reconsider the decision.
 
 FWIW, the D discord has had a few people coming to ask why 
 their code
 doesn't work when casting a `string` to a `char *`.
 
 I would pair such a cast error with a suggestion to use 
 `toStringz` in the
 case of string to char * conversions.
SDB 79
May 13 2023
prev sibling parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Sun, 30 Oct 2011 17:29:36 -0400, bearophile wrote:

 
 Do you see the bug I have found during the debugging?
 
 I think the D2 compiler has to catch this bug:
 
 *array = ...;
 
It is not a bug, it is a feature. If you really do not like it, use the .ptr property. :)
Nov 05 2011
parent reply Don <nospam nospam.com> writes:
On 05.11.2011 12:35, Dejan Lekic wrote:
 On Sun, 30 Oct 2011 17:29:36 -0400, bearophile wrote:

 Do you see the bug I have found during the debugging?

 I think the D2 compiler has to catch this bug:

 *array = ...;
It is not a bug, it is a feature. If you really do not like it, use the .ptr property. :)
It was a bug. And it's now been fixed.
Nov 05 2011
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
Don wrote:

 
 It was a bug. And it's now been fixed.
Don, care to explain why? If I want to treat D's array like I would do in C, why not allow me do so?
Nov 07 2011
parent Don <nospam nospam.com> writes:
On 07.11.2011 10:45, Dejan Lekic wrote:
 Don wrote:

 It was a bug. And it's now been fixed.
Don, care to explain why? If I want to treat D's array like I would do in C, why not allow me do so?
I had no involvement with it at all. Although, when we originally banned implicit conversions from arrays to pointers, it was because it was _the_ most common bug in D code. Especially when you pass a char[] array to an extern(C) function that accepts a char *. It really was a disaster. Just add .ptr if you want to convert it to a pointer. It's beautiful, really.
Nov 09 2011