Thread overview | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 07, 2021 This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
if (c !is null) Why????? Would it be simpler to type if (c is not null) on a related note. Why are not we allowed to do this? if (c != null) when other languages such as c#/java allow for it? -Alex |
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to 12345swordy | On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote: > if (c !is null) Why????? > > Would it be simpler to type > > if (c is not null) > > on a related note. Why are not we allowed to do this? > > if (c != null) it is allowed > > when other languages such as c#/java allow for it? > > -Alex "is" checks the address whereas "==" and "!=" eventually takes the path of operator overloading, i.e opEquals. |
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | On Thursday, 7 January 2021 at 05:14:44 UTC, Basile B. wrote:
> On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:
>> if (c !is null) Why?????
>>
>> Would it be simpler to type
>>
>> if (c is not null)
>>
>> on a related note. Why are not we allowed to do this?
>>
>> if (c != null)
>
> it is allowed
>
"For class objects, the == and != operators are intended to compare the contents of the objects, however an appropriate opEquals override must be defined for this to work. The default opEquals provided by the root Object class is equivalent to the is operator. Comparing against null is invalid, as null has no contents. Use the is and !is operators instead."
Not allowed for classes apparently.
-Alex
|
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to 12345swordy | On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:
> if (c !is null) Why?????
>
> Would it be simpler to type
>
> if (c is not null)
Saves 3 character per use, I guess. And keeps one operator in one keyword. Matter of taste, and whoever designed this obviously had to pick something.
|
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dukc | On Thursday, 7 January 2021 at 15:37:44 UTC, Dukc wrote:
> On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:
>> if (c !is null) Why?????
>>
>> Would it be simpler to type
>>
>> if (c is not null)
>
> Saves 3 character per use, I guess. And keeps one operator in one keyword. Matter of taste, and whoever designed this obviously had to pick something.
I don't think not is reserved anywhere else so it would mean adding a new terminal to the grammar too, and d already has a lot.
|
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to 12345swordy | On 1/7/21 9:13 AM, 12345swordy wrote:
> On Thursday, 7 January 2021 at 05:14:44 UTC, Basile B. wrote:
>> On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:
>>> if (c !is null) Why?????
>>>
>>> Would it be simpler to type
>>>
>>> if (c is not null)
>>>
>>> on a related note. Why are not we allowed to do this?
>>>
>>> if (c != null)
>>
>> it is allowed
>>
> "For class objects, the == and != operators are intended to compare the contents of the objects, however an appropriate opEquals override must be defined for this to work. The default opEquals provided by the root Object class is equivalent to the is operator. Comparing against null is invalid, as null has no contents. Use the is and !is operators instead."
>
> Not allowed for classes apparently.
Historically (before this restriction was added), when you compared 2 class objects, the code:
obj != expr
translated directly to:
!obj.opEquals(expr)
Which, if obj was null, resulted in a segmentation fault.
Thus the case of:
obj != null
is both error prone and ironic:
if(obj != null) { /* use obj */ }
This crashes if obj actually is null. Therefore, the syntax `obj !is null` is required.
You could find somewhere on these forums where I advocated for this, and Walter finally agreed.
Since then, the code for equality now translates to:
object.opEquals(obj1, obj2)
which will not crash, even if the object that isn't null improperly handles a comparison with null.
However, it's still more "correct" to say `is null` or `!is null`, as technically there's no other comparison that makes sense. So we *could* relax the restriction, but I think the existing expression is clearer.
-Steve
|
January 07, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Haughton | On Thursday, January 7, 2021 8:55:52 AM MST Max Haughton via Digitalmars-d wrote:
> On Thursday, 7 January 2021 at 15:37:44 UTC, Dukc wrote:
> > On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:
> >> if (c !is null) Why?????
> >>
> >> Would it be simpler to type
> >>
> >> if (c is not null)
> >
> > Saves 3 character per use, I guess. And keeps one operator in one keyword. Matter of taste, and whoever designed this obviously had to pick something.
>
> I don't think not is reserved anywhere else so it would mean adding a new terminal to the grammar too, and d already has a lot.
That and using ! is more consistent with what the C family of languages typically does. C-derived languages don't typically try to make sentences like "is not" would do. Having is and !is is also more consistent with == and !=. "is not" wouldn't really fit the rest of the language.
Ultimately, how you feel about it probably comes down primarily to taste and what you're used to, but I'm sure that Walter would have wanted to avoid adding an extra keyword just for this. So, I would have expected him to reject "is not" on that basis, but my guess is that he never even considered it. Once he'd decided on is, !is was probably simply the obvious choice given the other operators that D has and Walter's C/C++ background.
- Jonathan M Davis
|
January 09, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Thursday, 7 January 2021 at 22:42:40 UTC, Jonathan M Davis wrote: [...] > That and using ! is more consistent with what the C family of languages typically does. C-derived languages don't typically try to make sentences like "is not" would do. Having is and !is is also more consistent with == and !=. "is not" wouldn't really fit the rest of the language. Idiomatic C is of course [1] char *p = ... if (p) ... This form seems to be applicable for pointers in D, too. And also for class variables class C { ... C c; I wonder if there is a difference between if (c) and if (c ! is null). [1] https://stackoverflow.com/questions/3825668/checking-for-null-pointer-in-c-c/3825704#3825704 |
January 10, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to kdevel | On Saturday, January 9, 2021 2:02:33 PM MST kdevel via Digitalmars-d wrote:
> On Thursday, 7 January 2021 at 22:42:40 UTC, Jonathan M Davis wrote:
>
> [...]
>
> > That and using ! is more consistent with what the C family of languages typically does. C-derived languages don't typically try to make sentences like "is not" would do. Having is and !is is also more consistent with == and !=. "is not" wouldn't really fit the rest of the language.
>
> Idiomatic C is of course [1]
>
> char *p = ...
> if (p) ...
>
> This form seems to be applicable for pointers in D, too. And also for class variables
>
> class C { ...
> C c;
>
> I wonder if there is a difference between
>
> if (c)
>
> and
>
> if (c ! is null).
>
> [1] https://stackoverflow.com/questions/3825668/checking-for-null-pointer-in-c-c /3825704#3825704
IIRC, if the class overrides opCast for bool, then
if(c)
will cast the object to bool and use the result for the if condition, whereas
if(c !is null)
always checks whether the reference is null.
- Jonathan M Davis
|
January 10, 2021 Re: This syntax regarding null checking baffles me | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Sunday, 10 January 2021 at 10:42:48 UTC, Jonathan M Davis wrote:
[...]
> IIRC, if the class overrides opCast for bool, then
>
> if(c)
>
> will cast the object to bool and use the result for the if condition,
Well, no:
```null.d
import std.stdio: writeln;
class C {
bool opCast ()
{
return true;
}
}
void bar (C c)
{
if (c) writeln (3);
else writeln (2);
}
void foo (ref C c)
{
if (c) writeln (5);
else writeln (4);
}
void main ()
{
C c; // null ref
if (c) writeln (1);
else writeln (0);
bar (c);
foo (c);
auto x = cast (bool) c; // crash as expected
}
```
$ ./null
0
2
4
Segmentation fault
BTW: Correctly using variables of class or in case below of AA type
takes some getting used to. A few day ago I ran into a bug with a helper
function "merge" in a context like this:
```ini.d
import std.stdio;
void merge(T) (T a, T b)
{
foreach (k, v; b) {
if (k in a)
throw new Exception ("key <" ~ k ~ "> already set");
a[k] = v;
}
}
void main ()
{
string[string] data;
data = ["a": "A"]; // <---- comment me out! (*)
auto other_data = ["x": "X"];
data.merge (other_data);
writeln (data);
}
```
As expected one gets:
$ dmd ini.d && ./ini
["a":"A", "x":"X"]
Now it happened that in the course of development there was a code
path in which data was not initialized (*). Guess what the output was!
$ dmd ini.d && ./ini
[]
A void merge(T) (ref T a, T b) is required to cover the uninitialzed
case. That was a rather surprising experience.
|
Copyright © 1999-2021 by the D Language Foundation