digitalmars.D - This syntax regarding null checking baffles me
- 12345swordy (7/7) Jan 06 2021 if (c !is null) Why?????
- Basile B. (4/11) Jan 06 2021 "is" checks the address whereas "==" and "!=" eventually takes
- 12345swordy (9/20) Jan 07 2021 "For class objects, the == and != operators are intended to
- Steven Schveighoffer (23/44) Jan 07 2021 Historically (before this restriction was added), when you compared 2
- Dukc (4/7) Jan 07 2021 Saves 3 character per use, I guess. And keeps one operator in one
- Max Haughton (3/12) Jan 07 2021 I don't think not is reserved anywhere else so it would mean
- Jonathan M Davis (13/26) Jan 07 2021 That and using ! is more consistent with what the C family of languages
- kdevel (16/21) Jan 09 2021 On Thursday, 7 January 2021 at 22:42:40 UTC, Jonathan M Davis
- Jonathan M Davis (8/30) Jan 10 2021 IIRC, if the class overrides opCast for bool, then
- kdevel (72/76) Jan 10 2021 On Sunday, 10 January 2021 at 10:42:48 UTC, Jonathan M Davis
- Paul Backus (3/21) Jan 10 2021 Your opCast has the wrong signature. It should be:
- kdevel (44/47) Jan 10 2021 "Wrong" in what respect?
- Paul Backus (3/7) Jan 10 2021 It does not match the signature required by the language spec:
- kdevel (33/44) Jan 10 2021 Sure, but it is called anyway:
- Steven Schveighoffer (9/64) Jan 11 2021 That's a relic from D1:
- ag0aep6g (8/14) Jan 10 2021 You're misremembering. Or maybe it was changed since you last
- Imperatorn (7/14) Jan 11 2021 One thing you could do is to make an "extension method", exploit
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) -Alex
Jan 06 2021
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-Alex"is" checks the address whereas "==" and "!=" eventually takes the path of operator overloading, i.e opEquals.
Jan 06 2021
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:"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. -Alexif (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
Jan 07 2021
On 1/7/21 9:13 AM, 12345swordy wrote:On Thursday, 7 January 2021 at 05:14:44 UTC, Basile B. wrote: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. -SteveOn Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote:"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.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
Jan 07 2021
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.
Jan 07 2021
On Thursday, 7 January 2021 at 15:37:44 UTC, Dukc wrote:On Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote: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.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.
Jan 07 2021
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: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 DavisOn Thursday, 7 January 2021 at 04:57:55 UTC, 12345swordy wrote: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.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.
Jan 07 2021
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
Jan 09 2021
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: [...]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 DavisThat 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
Jan 10 2021
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.
Jan 10 2021
On Sunday, 10 January 2021 at 14:40:04 UTC, kdevel wrote:On Sunday, 10 January 2021 at 10:42:48 UTC, Jonathan M Davis wrote: [...]Your opCast has the wrong signature. It should be: bool opCast(T : bool)()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; } }
Jan 10 2021
On Sunday, 10 January 2021 at 16:44:29 UTC, Paul Backus wrote: [...]Your opCast has the wrong signature."Wrong" in what respect?It should be: bool opCast(T : bool)()"My" opCast works as expected: ```null2.d import std.stdio: writeln; class C { int i; bool opCast () { __PRETTY_FUNCTION__.writeln; 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 = new C; writeln (c); if (c) writeln (1); else writeln (0); bar (c); foo (c); cast (bool) c; // print bool null2.C.opCast() c = null; cast (bool) c; // Segmentation fault } ``` $ dmd null2 && ./null2 null2.C 1 3 5 bool null2.C.opCast() Segmentation fault
Jan 10 2021
On Sunday, 10 January 2021 at 17:28:42 UTC, kdevel wrote:On Sunday, 10 January 2021 at 16:44:29 UTC, Paul Backus wrote: [...]It does not match the signature required by the language spec: https://dlang.org/spec/operatoroverloading.html#castYour opCast has the wrong signature."Wrong" in what respect?
Jan 10 2021
On Sunday, 10 January 2021 at 19:21:47 UTC, Paul Backus wrote:On Sunday, 10 January 2021 at 17:28:42 UTC, kdevel wrote:Sure, but it is called anyway: ```null3.d import std.stdio: writeln; class C { int i; bool opCast () { __PRETTY_FUNCTION__.writeln; return false; } } void main () { C c = new C; cast (bool) c; // print bool null3.C.opCast() c = null; cast (bool) c; // Segmentation fault } ``` $ dmd null3 && ./null3 bool null3.C.opCast() Segmentation fault As ag0aep6g pointed out if (c) does not invoke the opCast member. Neither one of the signatures bool opCast () T opCast (T: bool) (). This "conversion to bool" [1] of the class variable seems to be not programmatically accessible. [1] "Class references are converted to bool by checking to see if the class reference is null or not." from § 20.2.1On Sunday, 10 January 2021 at 16:44:29 UTC, Paul Backus wrote: [...]It does not match the signature required by the language spec: https://dlang.org/spec/operatoroverloading.html#castYour opCast has the wrong signature."Wrong" in what respect?
Jan 10 2021
On 1/10/21 4:52 PM, kdevel wrote:On Sunday, 10 January 2021 at 19:21:47 UTC, Paul Backus wrote:That's a relic from D1: https://digitalmars.com/d/1.0/operatoroverloading.html#Unary IMO, that functionality should not be used, but I doubt we will ever remove it. (I tested, and using this form works for if(s) for a struct) Note also that assert(c) will check the invariant of the object if it's not null. D has a few hidden behaviors for truthiness. -SteveOn Sunday, 10 January 2021 at 17:28:42 UTC, kdevel wrote:Sure, but it is called anyway: ```null3.d import std.stdio: writeln; class C { int i; bool opCast () { __PRETTY_FUNCTION__.writeln; return false; } } void main () { C c = new C; cast (bool) c; // print bool null3.C.opCast() c = null; cast (bool) c; // Segmentation fault } ``` $ dmd null3 && ./null3 bool null3.C.opCast() Segmentation fault As ag0aep6g pointed out if (c) does not invoke the opCast member. Neither one of the signatures bool opCast () T opCast (T: bool) (). This "conversion to bool" [1] of the class variable seems to be not programmatically accessible. [1] "Class references are converted to bool by checking to see if the class reference is null or not." from § 20.2.1On Sunday, 10 January 2021 at 16:44:29 UTC, Paul Backus wrote: [...]It does not match the signature required by the language spec: https://dlang.org/spec/operatoroverloading.html#castYour opCast has the wrong signature."Wrong" in what respect?
Jan 11 2021
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, whereas if(c !is null) always checks whether the reference is null.You're misremembering. Or maybe it was changed since you last checked. A rewrite from `if (c)` to `if (c.opCast!bool)` "only happens, however, for instances of structs. Class references are converted to bool by checking to see if the class reference is null or not." https://dlang.org/spec/operatoroverloading.html#boolean_operators
Jan 10 2021
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) -AlexOne thing you could do is to make an "extension method", exploit ufcs and do like c.isNull instead. Maybe those already exists somewhere. operators. Also, strings for example have string.IsNullOrEmpty and IsNullOrWhiteSpace, those are handy.
Jan 11 2021