October 31, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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.
|
October 31, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 |
October 31, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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. |
October 31, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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.
|
November 01, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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 |
November 01, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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"); } |
November 02, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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 |
November 02, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | > 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 |
November 02, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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.
|
November 02, 2011 Re: Disallow arrays as pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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.
|
Copyright © 1999-2021 by the D Language Foundation