www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - char[] == null

reply Spacen Jasset <spacen razemail.com> writes:
Should this be allowed? What is it's purpose? It could compare 
two arrays, but surely not that each element of type char is null?

char[] buffer;
if (buffer == null) {}
Nov 18 2015
next sibling parent reply rsw0x <anonymous anonymous.com> writes:
On Wednesday, 18 November 2015 at 20:57:08 UTC, Spacen Jasset 
wrote:
 Should this be allowed? What is it's purpose? It could compare 
 two arrays, but surely not that each element of type char is 
 null?

 char[] buffer;
 if (buffer == null) {}
slices aren't arrays http://dlang.org/d-array-article.html
Nov 18 2015
parent reply anonymous <anonymous example.com> writes:
On 18.11.2015 22:02, rsw0x wrote:
 slices aren't arrays
 http://dlang.org/d-array-article.html
The language reference/specification [1] uses the term "dynamic array" for T[] types. Let's not enforce a slang that's different from that. [1] http://dlang.org/arrays.html
Nov 18 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, November 18, 2015 22:15:19 anonymous via Digitalmars-d-learn
wrote:
 On 18.11.2015 22:02, rsw0x wrote:
 slices aren't arrays
 http://dlang.org/d-array-article.html
The language reference/specification [1] uses the term "dynamic array" for T[] types. Let's not enforce a slang that's different from that. [1] http://dlang.org/arrays.html
Exactly. T[] _is_ a dynamic array. Steven's otherwise wonderful article on arrays in D ( http://dlang.org/d-array-article.html ) made the mistake of calling the buffer that T[] points to on the GC heap (assuming that even does point to the GC heap) the dynamic array. And per the language spec, that's not true at all. T[] is a dynamic array, whereas T[n] is a static array. The buffer referred to by T[] has no official name. And actually, the dynamic array really doesn't care whether it refers to a buffer on the GC heap, on that was malloced, a slice of a static array, etc. All of its operations are the same regardless, and all of the work. It's just that if the dynamic array does not refer to a buffer allocated on the GC heap for dynamic arrays, then it doesn't have any excess capacity for the dynamic array to grow into when you append to it, so appending to it forces the GC to reallocate its memory (as opposed to only having to reallocate sometimes when the buffer is already GC-allocated). And since the dynamic array itself does not manage its own memory, if you slice something other than GC-allocated memory to get a dynamic array, then it's up to you to make sure that you don't leak that memory or refer to it after it's been freed. However, every other aspect of T[] is identical regardless of what memory backs it, and most code really doesn't care what memory backs it. As far as the D language is concern, T[] _is_ a slice of memory, but it's also a dynamic array, whereas the memory that it's slicing is _not_ a dynamic array. - Jonathan M Davis
Nov 19 2015
next sibling parent reply Spacen Jasset <spacen razemail.com> writes:
On Thursday, 19 November 2015 at 08:30:54 UTC, Jonathan M Davis 
wrote:
 On Wednesday, November 18, 2015 22:15:19 anonymous via 
 Digitalmars-d-learn wrote:
 [...]
Exactly. T[] _is_ a dynamic array. Steven's otherwise wonderful article on arrays in D ( http://dlang.org/d-array-article.html ) made the mistake of calling the buffer that T[] points to on the GC heap (assuming that even does point to the GC heap) the dynamic array. And per the language spec, that's not true at all. [...]
I mentioned this because it's bit of an error trap, that I fell into. char[] == null vs char[] is null Is there any good use for char[] == null ? If not, a warning might be helpful.
Nov 19 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 11/19/15 5:04 AM, Spacen Jasset wrote:
 On Thursday, 19 November 2015 at 08:30:54 UTC, Jonathan M Davis wrote:
 On Wednesday, November 18, 2015 22:15:19 anonymous via
 Digitalmars-d-learn wrote:
 [...]
Exactly. T[] _is_ a dynamic array. Steven's otherwise wonderful article on arrays in D ( http://dlang.org/d-array-article.html ) made the mistake of calling the buffer that T[] points to on the GC heap (assuming that even does point to the GC heap) the dynamic array. And per the language spec, that's not true at all. [...]
I mentioned this because it's bit of an error trap, that I fell into. char[] == null vs char[] is null Is there any good use for char[] == null ? If not, a warning might be helpful.
Of course, if you are comparing something to an empty array, null is an effective literal to create one. -Steve
Nov 19 2015
prev sibling parent Kagamin <spam here.lot> writes:
On Thursday, 19 November 2015 at 10:04:37 UTC, Spacen Jasset 
wrote:
 char[] == null
 vs
 char[] is null

 Is there any good use for char[] == null ? If not, a warning 
 might be helpful.
Actually char[] == null is a more usable one.
Nov 19 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 11/19/15 3:30 AM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Wednesday, November 18, 2015 22:15:19 anonymous via Digitalmars-d-learn
wrote:
 On 18.11.2015 22:02, rsw0x wrote:
 slices aren't arrays
 http://dlang.org/d-array-article.html
The language reference/specification [1] uses the term "dynamic array" for T[] types. Let's not enforce a slang that's different from that. [1] http://dlang.org/arrays.html
Exactly. T[] _is_ a dynamic array. Steven's otherwise wonderful article on arrays in D ( http://dlang.org/d-array-article.html ) made the mistake of calling the buffer that T[] points to on the GC heap (assuming that even does point to the GC heap) the dynamic array. And per the language spec, that's not true at all.
It was not a mistake :) It's how I still think of it. The spec is confusing, and my terminology, IMO, is a much more consistent (and accurate) way to think of it. -Steve
Nov 19 2015
parent Maxim Fomin <mxfomin gmail.com> writes:
On Thursday, 19 November 2015 at 15:36:44 UTC, Steven 
Schveighoffer wrote:
 On 11/19/15 3:30 AM, Jonathan M Davis via Digitalmars-d-learn 
 wrote:
 On Wednesday, November 18, 2015 22:15:19 anonymous via 
 Digitalmars-d-learn wrote:
 On 18.11.2015 22:02, rsw0x wrote:
 slices aren't arrays
 http://dlang.org/d-array-article.html
The language reference/specification [1] uses the term "dynamic array" for T[] types. Let's not enforce a slang that's different from that. [1] http://dlang.org/arrays.html
Exactly. T[] _is_ a dynamic array. Steven's otherwise wonderful article on arrays in D ( http://dlang.org/d-array-article.html ) made the mistake of calling the buffer that T[] points to on the GC heap (assuming that even does point to the GC heap) the dynamic array. And per the language spec, that's not true at all.
It was not a mistake :) It's how I still think of it. The spec is confusing, and my terminology, IMO, is a much more consistent (and accurate) way to think of it. -Steve
Why formal definition of dynamic array caused confusion and is inconsistent? It is well consistent with static array and other aggregate types notions. Consider this: int *x = new int; // this is 'int type' ans it is 'dynamic' int y; int *a = &y; // and this is not 'int type' The problem is treating chunk of heap memory as some kind of type (dynamic in this case). Type of object determines an interface of interacting with object while storage determines memory location and possibly duration of lifetime. It is possible to have object of any type to be allocated on different storages - for example, slice does not necessarily points to dynamic array (in your terms). C and C++ established a long tradition of such standard notions as object, lifetime, storage and type. From system language perspective calling memory a type (in other words, type of object depends on where it was allocated) does not make much sense.
Nov 20 2015
prev sibling next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Wed, 18 Nov 2015 20:57:06 +0000, Spacen Jasset wrote:

 Should this be allowed? What is it's purpose? It could compare two
 arrays, but surely not that each element of type char is null?
 
 char[] buffer;
 if (buffer == null) {}
'null' is a value of ambiguous type. The compiler finds a set of compatible types for them by applying known implicit conversions. 'null' can implicitly convert to 'char[]'. Arrays, of course, are tuples consisting of a start pointer and length. A null array is essentially {ptr = null, length = 0}. Array equality is implemented as, roughly: --- if (a.length != b.length) return false; foreach (i, v; a) { if (v != b[i]) return false; } return true; --- (That's not quite how it's implemented; it uses runtime functions and indirection. But it's the same algorithm.) This shows us that all 0-length arrays are equal. Pretty much as we'd expect. So your code is equivalent to: --- char[] buffer; if (buffer.length == 0) {} ---
Nov 18 2015
parent reply Meta <jared771 gmail.com> writes:
On Wednesday, 18 November 2015 at 23:53:01 UTC, Chris Wright 
wrote:
 ---
 char[] buffer;
 if (buffer.length == 0) {}
 ---
This is not true. Consider the following code: import std.stdio; void main() { int[] a = [0, 1, 2]; //4002E000 3 writeln(a.ptr, " ", a.length); //Is not triggered, obviously assert(a == null); a.length = 0; //4002E000 0 writeln(a.ptr, " ", a.length, " ", a); //Is not triggered, not as obvious assert(a == null); } There are cases when an array may have 0 length but a non-null pointer. If you want to check if an array's length is 0, you must explicitly check its length member. Checking if an array is equal to null only compares its pointer field to null. It does *not* check the length.
Nov 18 2015
next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Thu, 19 Nov 2015 03:53:46 +0000, Meta wrote:

 On Wednesday, 18 November 2015 at 23:53:01 UTC, Chris Wright wrote:
 ---
 char[] buffer;
 if (buffer.length == 0) {}
 ---
This is not true. Consider the following code: import std.stdio; void main() { int[] a = [0, 1, 2]; //4002E000 3 writeln(a.ptr, " ", a.length); //Is not triggered, obviously assert(a == null); a.length = 0; //4002E000 0 writeln(a.ptr, " ", a.length, " ", a); //Is not triggered, not as obvious assert(a == null); } There are cases when an array may have 0 length but a non-null pointer. If you want to check if an array's length is 0, you must explicitly check its length member. Checking if an array is equal to null only compares its pointer field to null. It does *not* check the length.
I tested the behavior and it matches what I said earlier: --- auto c = "hello world".dup; auto b = c[0..0]; writeln(b == null); // prints true writeln(b.ptr == null); // prints false --- This is because array comparison is a memberwise comparison and not a reference comparison, as you can see more clearly with: --- enum int[] a = [1, 2, 3]; writeln(a == a.dup); // prints true --- Or you can check the runtime's implementation of array equality at https://github.com/D-Programming-Language/druntime/blob/master/src/ object.d#L437 . Just for fun, is an array ever not equal to itself?
Nov 18 2015
parent reply anonymous <anonymous example.com> writes:
On 19.11.2015 06:18, Chris Wright wrote:
 Just for fun, is an array ever not equal to itself?
Yes, when it contains an element that's not equal to itself, e.g. NaN.
Nov 18 2015
parent Chris Wright <dhasenan gmail.com> writes:
On Thu, 19 Nov 2015 07:28:28 +0100, anonymous wrote:

 On 19.11.2015 06:18, Chris Wright wrote:
 Just for fun, is an array ever not equal to itself?
Yes, when it contains an element that's not equal to itself, e.g. NaN.
Exactly. If NaN-like cases didn't exist, TypeInfo_Array could have an optimization: if the pointers and lengths of its inputs were both equal, the arrays are equal. But adding this optimization would result in problematic behavior. Specifically: auto a = [float.nan]; assert(a == a); // passes under proposed optimization, fails now assert(a == a.dup); // fails under proposed optimization, fails now
Nov 19 2015
prev sibling next sibling parent reply Jack Applegame <japplegame gmail.com> writes:
On Thursday, 19 November 2015 at 03:53:48 UTC, Meta wrote:
 On Wednesday, 18 November 2015 at 23:53:01 UTC, Chris Wright 
 wrote:
 [...]
This is not true. Consider the following code: import std.stdio; void main() { int[] a = [0, 1, 2]; //4002E000 3 writeln(a.ptr, " ", a.length); //Is not triggered, obviously assert(a == null); a.length = 0; //4002E000 0 writeln(a.ptr, " ", a.length, " ", a); //Is not triggered, not as obvious assert(a == null); } There are cases when an array may have 0 length but a non-null pointer. If you want to check if an array's length is 0, you must explicitly check its length member. Checking if an array is equal to null only compares its pointer field to null. It does *not* check the length.
Really? http://dpaste.dzfl.pl/b11346e8e341
Nov 18 2015
parent reply Meta <jared771 gmail.com> writes:
On Thursday, 19 November 2015 at 06:57:20 UTC, Jack Applegame 
wrote:
 Really? http://dpaste.dzfl.pl/b11346e8e341
Sorry, I said the exact opposite of what I meant to say. The `assert(a == null)` *is* triggered because the expression `a == null` fails, even though a.length == 0. You should not use `a == null` to check if an array is empty. Always use a.length == 0.
Nov 19 2015
parent Meta <jared771 gmail.com> writes:
On Thursday, 19 November 2015 at 13:49:18 UTC, Meta wrote:
 On Thursday, 19 November 2015 at 06:57:20 UTC, Jack Applegame 
 wrote:
 Really? http://dpaste.dzfl.pl/b11346e8e341
Sorry, I said the exact opposite of what I meant to say. The `assert(a == null)` *is* triggered because the expression `a == null` fails, even though a.length == 0. You should not use `a == null` to check if an array is empty. Always use a.length == 0.
Actually, no it's not. Never mind.
Nov 19 2015
prev sibling parent Kagamin <spam here.lot> writes:
On Thursday, 19 November 2015 at 03:53:48 UTC, Meta wrote:
 On Wednesday, 18 November 2015 at 23:53:01 UTC, Chris Wright 
 wrote:
 ---
 char[] buffer;
 if (buffer.length == 0) {}
 ---
This is not true. Consider the following code: import std.stdio; void main() { int[] a = [0, 1, 2]; //4002E000 3 writeln(a.ptr, " ", a.length); //Is not triggered, obviously assert(a == null); a.length = 0; //4002E000 0 writeln(a.ptr, " ", a.length, " ", a); //Is not triggered, not as obvious assert(a == null); } There are cases when an array may have 0 length but a non-null pointer. If you want to check if an array's length is 0, you must explicitly check its length member. Checking if an array is equal to null only compares its pointer field to null. It does *not* check the length.
Comparison is ok, weird behavior manifests in boolean context: void main() { int[] a = [0, 1, 2]; //4002E000 3 assert(a != null); assert(!!a); //passes, ok a.length = 0; //4002E000 0 assert(a == null); assert(!!a); //still passes! }
Nov 19 2015
prev sibling parent reply BBaz <b2.temp gmx.com> writes:
On Wednesday, 18 November 2015 at 20:57:08 UTC, Spacen Jasset 
wrote:
 Should this be allowed ?
IMHO no. It's better to use `.length` to test if an array is empty. Why ? Because the day you'll have a function whose parameter is a pointer to an array, comparing to null will become completly confusing: --- void whyPeopleShouldUseLength(char[]* buffptr) { if (buffptr != null && buffptr.length > 0) {} } --- Here you really have to test if the variable is assigned, it's not a shortcut to test the internal buffptr `.ptr` member.
Nov 19 2015
parent Jack Applegame <japplegame gmail.com> writes:
I prefer

import std.array;
if(!arr.empty) {}
Nov 19 2015