March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Phil Lavoie | On Monday, March 25, 2013 18:18:00 Phil Lavoie wrote: > Nothing is wrong with that apparently. I was not aware arr.length tolerated null slices. Does it keeps its behavior in unsafe or system mode? If you haven't read this article on arrays, then you should: http://dlang.org/d-array-article.html An array in D is basically (though not exactly) struct A(T) { A ptr; size_t length; } Almost nothing cares about if ptr is null. If you're checking length, then it just checks length (which is 0 if ptr is null). If you append to it or set length, then the runtime will look at ptr and allocate or reallocate it if it needs to (or just increase length if it can do so). == does something along the lines of if(lhs.length != rhs.length) return false; if(lhs.ptr is rhs.ptr) return true; for(size_t i = 0; i < lhs.length; ++i) { if(lhs[i] != rhs[i]) return false; } return true; So, it doesn't care one whit whether ptr is null or not. Almost nothing cares. About the only thing that cares is the is operator - i.e. arr is null. However, the problem here is that cast(bool)arr returns whether arr.ptr is null rather than arr.length == 0, which is inconsistent with almost everything else that goes on with arrays, and so it's error-prone. - Jonathan M Davis |
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Monday, 25 March 2013 at 17:25:13 UTC, Timon Gehr wrote:
> On 03/25/2013 06:13 PM, Phil Lavoie wrote:
>> ...
>>
>> However, testing for null is kinda useful :)
>> ...
>
> It is currently basically useless for array slices, because relying on it is brittle.
Well, since they CAN be null, it is at least useful in contracts programming.
void foo( int[] zeSlice ) in {
assert( zeSlice !is null, "passing null slice" )
} body {
}
Also, imagine, for some reasons, you have that
string[ ( int[] ) ] mapOfSlices;
...
//initialize all strings, but make sure their corresding slices are null, because an empty slice has a different meaning.
auto aSlice = mapOfSlices.get( "toto", null );
Still comparing against null, since it has a different meaning, maybe null means not found and empty means found but without value.
|
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
On Monday, March 25, 2013 13:32:36 Jonathan M Davis wrote:
> However, the problem here is that cast(bool)arr returns whether
> arr.ptr is null rather than arr.length == 0, which is inconsistent with
> almost everything else that goes on with arrays, and so it's error-prone.
Actually, that should be that returns whether arr !s null rather than arr.length != 0, but you get the idea.
- Jonathan M Davis
|
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
On Monday, March 25, 2013 10:29:46 H. S. Teoh wrote: > On Mon, Mar 25, 2013 at 01:15:59PM -0400, Jonathan M Davis wrote: > > On Monday, March 25, 2013 17:43:24 Phil Lavoie wrote: > > > I do believe that, in any case, this form is best: > > > if( arr !is null && !arr.empty ) > > > > That's utterly pointless. empty checks that length == 0, and length == 0 if the array is null. It can be useful to check whether an array is null with the is operator for cases where that's used to indicate that a result wasn't found or something like that, but very little cares about the difference between a null array and an empty one, and attempting to treat them as different tends to be very error-prone. > > > > I don't really like how null works with arrays, since it's generally treated as the same as an empty array (including for ==), but that's the way it works in D, and you just have to deal with it. And given how arrays in D work in general, having if(arr) check specifically for null rather than empty is definitely error-prone. > > [...] > > I think this is all just a storm in a teacup. Just use .length: > > import std.stdio; > > void main() { > int[] a; > writeln(a is null); // prints true > writeln(a.length); // prints 0 > > a ~= 1; > a.length = 0; > writeln(a is null); // prints false > writeln(a.length); // prints 0 > } > > So just use "if (a.length > 0)" and you're fine. > > The distinction between null and non-null for arrays is, IMO, an implementation-specific detail that should not be relied upon. You can rely on null being null, and you can rely on any array that you've explictly set to null being null as long as no other mutating operations are used on it. That's guaranteed. > In my > mind, it's the implementation that gets to decide when an array should > be null and when it shouldn't. User code had better not be dependent on > that kind of detail. If you *really* need to tell the difference, just > use Nullable to wrap around the array. It can be valuable to have a function which returns an array specifically return null to indicate something, and I believe that Phobos does this in some places. But that's about the only place that it's safe to rely on an array being null, as it returned null explicitly. It's relying on an array being null when it was not explicitly set to null which doesn't work. - Jonathan M Davis |
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Phil Lavoie | On Mon, Mar 25, 2013 at 06:34:23PM +0100, Phil Lavoie wrote: [...] > Still comparing against null, since it has a different meaning, maybe null means not found and empty means found but without value. If you want to make this distinction, use std.typecons.Nullable. T -- Obviously, some things aren't very obvious. |
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Phil Lavoie | On Monday, March 25, 2013 18:34:23 Phil Lavoie wrote: > On Monday, 25 March 2013 at 17:25:13 UTC, Timon Gehr wrote: > > On 03/25/2013 06:13 PM, Phil Lavoie wrote: > >> ... > >> > >> However, testing for null is kinda useful :) > >> ... > > > > It is currently basically useless for array slices, because relying on it is brittle. > > Well, since they CAN be null, it is at least useful in contracts > programming. > void foo( int[] zeSlice ) in { > assert( zeSlice !is null, "passing null slice" ) > } body { > > } But why would you care? Almost nothing cares about the difference between a null array and an empty array, and unless a function is treating null as something explicitly different from empty (which is generally a bad idea), it really isn't going to care. All of the various array operations will treat them the same. > Also, imagine, for some reasons, you have that > string[ ( int[] ) ] mapOfSlices; > ... > //initialize all strings, but make sure their corresding slices > are null, because an empty slice has a different meaning. > > auto aSlice = mapOfSlices.get( "toto", null ); > > Still comparing against null, since it has a different meaning, maybe null means not found and empty means found but without value. In general, relying on a null array and an empty array having different meanings is just begging for trouble. About the only places that I would even consider doing so is a member variable which is explicitly set to null to indicate the lack of a value (and even then, using Nullable might be a good idea for clarity and to reduce the risk of bugs) or a function which returns null to indicate something different from a valid value (like not found). - Jonathan M Davis |
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Monday, 25 March 2013 at 17:40:27 UTC, H. S. Teoh wrote:
> On Mon, Mar 25, 2013 at 06:34:23PM +0100, Phil Lavoie wrote:
> [...]
>> Still comparing against null, since it has a different meaning,
>> maybe null means not found and empty means found but without value.
>
> If you want to make this distinction, use std.typecons.Nullable.
>
>
> T
Well, Nullable just acts as if it could be null. Why would I use it when I got a type that can be null, without overhead?
Are you saying that they are planning to remove null for slices? Because if you're not then I truly don't see what's your point.
|
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Phil Lavoie | Phil Lavoie:
> I was not aware arr.length tolerated null slices. Does it keeps its behavior in unsafe or system mode?
That behaviour is always kept. Because the underlying data structure doesn't change.
Bye,
bearophile
|
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Monday, 25 March 2013 at 17:44:42 UTC, Jonathan M Davis wrote:
> On Monday, March 25, 2013 18:34:23 Phil Lavoie wrote:
>> On Monday, 25 March 2013 at 17:25:13 UTC, Timon Gehr wrote:
>> > On 03/25/2013 06:13 PM, Phil Lavoie wrote:
>> >> ...
>> >>
>> >> However, testing for null is kinda useful :)
>> >> ...
>> >
>> > It is currently basically useless for array slices, because
>> > relying on it is brittle.
>>
>> Well, since they CAN be null, it is at least useful in contracts
>> programming.
>> void foo( int[] zeSlice ) in {
>> assert( zeSlice !is null, "passing null slice" )
>> } body {
>>
>> }
>
> But why would you care? Almost nothing cares about the difference between a
> null array and an empty array, and unless a function is treating null as
> something explicitly different from empty (which is generally a bad idea), it
> really isn't going to care. All of the various array operations will treat
> them the same.
I wrote it before reading your post on everything regarding length. I realize now it makes less sense, though there is still the possibility of having a special case for nulls, I mean, this is why Nullable exists in the first place, right?
All I'm saying is, there is no point for me to use Nullable for types that I know can be null unless somebody plans on removing null for that type. I'm not sure how much clarity doing var.isNull vs. var is null is going to add for an already nullable type?
Regarding the if(dynamic_array) issue, I am not in favor of keeping it. I just think that it currently does exactly what I expect from it (though I don't use it), and I'm not sure how much changing it would be helpful. I understand that you think it should test for length, I'm just saying this maybe ain't the predictable behavior for everybody.
Phil
|
March 25, 2013 Re: Forbid dynamic arrays in boolean evaluation contexts | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Monday, 25 March 2013 at 17:55:22 UTC, bearophile wrote:
> Phil Lavoie:
>
>> I was not aware arr.length tolerated null slices. Does it keeps its behavior in unsafe or system mode?
>
> That behaviour is always kept. Because the underlying data structure doesn't change.
>
> Bye,
> bearophile
Good to know, thanks.
Phil
|
Copyright © 1999-2021 by the D Language Foundation