www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is there a simple way to check if value is null for every case?

reply SG <s g.com> writes:
Hi again,

The code below works for some cases but not for the Nullable!Type.

A way to fix it should be check the type and use ".isNull" for 
Nullabe!Type. But is there a simple way to test if value is null 
for every case?


import std.stdio, std.typecons, std.variant, std.conv;

bool foo(T)(T t){
     return (t is null);
}

class S{
     Nullable!int i;
}

void main(){
     string x = "a";
     writeln(x is null," - " ,x.foo);

     string y = null;
     writeln(y is null," - ", y.foo);

     auto z = null;
     writeln(z is null," - ", z.foo);


     S s = new S();
     writeln(s.i.isNull); // Ok

     //writeln(s.i is null); // Error
     //s.i.foo(2); // Error
}
Aug 26 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 27/08/2018 4:37 AM, SG wrote:
 Hi again,
 
 The code below works for some cases but not for the Nullable!Type.
 
 A way to fix it should be check the type and use ".isNull" for 
 Nullabe!Type. But is there a simple way to test if value is null for 
 every case?
 
 
 import std.stdio, std.typecons, std.variant, std.conv;
 
 bool foo(T)(T t){
      return (t is null);
 }
 
 class S{
      Nullable!int i;
 }
 
 void main(){
      string x = "a";
      writeln(x is null," - " ,x.foo);
 
      string y = null;
      writeln(y is null," - ", y.foo);
 
      auto z = null;
      writeln(z is null," - ", z.foo);
 
 
      S s = new S();
      writeln(s.i.isNull); // Ok
 
      //writeln(s.i is null); // Error
      //s.i.foo(2); // Error
 }
UFCS function called isNull. e.g. import std.traits : isPointer; bool isNull(T)(T value) if (is(T == class) || isPointer!T) { return value is null; }
Aug 26 2018
parent reply SG <s g.com> writes:
On Sunday, 26 August 2018 at 16:39:53 UTC, rikki cattermole wrote:
 UFCS function called isNull.

 e.g.

 import std.traits : isPointer;
 bool isNull(T)(T value) if (is(T == class) || isPointer!T) {
 	return value is null;
 }
Hi Rikki, I'm still confused, I want to create a extension for checking null for every type, so in D I'll need to handle each case with Templates? x == null; myObject == null; myObject.i == null; myStruct == null; myStruct.j == null; But again, in D I'll need the check the type? Is possible to make one Template for all cases? The code below works, but I don't think this is a right thing to do, right? import std.stdio, std.typecons, std.variant, std.conv; import std.traits : isPointer; bool foo(T)(T value) if (is(T == VariantN!32LU)) { return value == null; } bool foo(T)(T value) if (is(T == Nullable!int) || isPointer!T) { return value.isNull; } bool foo(T)(T t) if (!is(T == Nullable!int) && !is(T == VariantN!32LU)){ if (is(T == typeof(null))){ return true; } return (t is null); } class S{ Nullable!int i; } void main(){ Variant v = null; writeln(v == null," - " ,v.foo); Variant v2 = "a"; writeln(v2 == null," - " ,v2.foo); string x = "a"; writeln(x is null," - " ,x.foo); string y = null; writeln(y is null," - ", y.foo); auto z = null; writeln(z is null," - ", z.foo); S s = new S(); writeln(s.i.isNull," - ", s.i.foo); }
Aug 26 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 27/08/2018 12:51 PM, SG wrote:
 On Sunday, 26 August 2018 at 16:39:53 UTC, rikki cattermole wrote:
 UFCS function called isNull.

 e.g.

 import std.traits : isPointer;
 bool isNull(T)(T value) if (is(T == class) || isPointer!T) {
     return value is null;
 }
Hi Rikki, I'm still confused, I want to create a extension for checking null for every type, so in D I'll need to handle each case with Templates?
Templates make it the easiest way, since common patterns, like arrays, classes and pointers have the exact same null check syntax.

 
 x == null;
 myObject == null;
 myObject.i == null;
 myStruct == null;
 myStruct.j == null;
 

type. Which it would not work for.
 But again, in D I'll need the check the type? Is possible to make one 
 Template for all cases?
 
 The code below works, but I don't think this is a right thing to do, right?
You don't need isNull function for Nullable because it has a method called it. That will be preferred (hence I specifically used isNull as the name). For Variant, use hasValue. bool isNull(Variant value) { return !value.hasValue; } Writing a Unified Function Call Syntax function isn't really an extension. You're defining a function that is to be preferred when you ask for a method of the same name. So that it appears as if it was actually described as a method instead of a free-function (not attached to class/interface/struct/union).
Aug 26 2018
parent reply SG <s g.com> writes:
On Monday, 27 August 2018 at 03:21:04 UTC, rikki cattermole wrote:
 Templates make it the easiest way, since common patterns, like 
 arrays, classes and pointers have the exact same null check 
 syntax.
I see.

 value type. Which it would not work for.
Struct S{ public int? i; } S.i == null; // This works nicely.
 You don't need isNull function for Nullable because it has a 
 method called it. That will be preferred (hence I specifically 
 used isNull as the name).

 For Variant, use hasValue.

 bool isNull(Variant value) {
 	return !value.hasValue;
 }
The problem I'm trying to solve is beyond that. This is just an example. But bear with me, right now all I want is a function to check the value from 'a' type and return if it is null. The type could be a: Class, Struct, a Basic data type, Variant, Nullable and so. at least for this same case, I would write the same thing in few lines to perform it, in D I found very hard. Isn't counter intuitive the way D works? Because for each type Class/Nullable you check with .isNull, for Variant with .hasValue, for string (variable is null). Thanks.
Aug 27 2018
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 28/08/2018 12:54 AM, SG wrote:

 
 Struct S{
     public int? i;
 }
 
 S.i == null; // This works nicely.
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/index support.
Aug 27 2018
parent reply SG <s g.com> writes:
On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole wrote:

 language support.
The big difference is that in there I could do: int? i = null; string j = null; var k = null; and test all like: i == null; j == null; k == null; but in D: Nullable!int i; auto j = null; string k = null; writefln("%s", i.isNull); // I need to invoke Nullable property isNull; writefln("%s", i == null); // I can't just do this. writefln("%s", j == null); writefln("%s", k == null);
Aug 27 2018
next sibling parent Jacob Shtokolov <jacob.100205 gmail.com> writes:
On Monday, 27 August 2018 at 14:11:32 UTC, SG wrote:
 On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole 
 wrote:

 language support.
Shouldn't it be in the standard library? I think it's worth it to create a feature request in Phobos for that. Or at least make a bug report. Such inconsistencies must be handled by a standard library, not manually, I believe.
Aug 27 2018
prev sibling parent reply aliak <something something.com> writes:
On Monday, 27 August 2018 at 14:11:32 UTC, SG wrote:
 On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole 
 wrote:

 language support.
The big difference is that in there I could do: int? i = null; string j = null; var k = null; and test all like: i == null; j == null; k == null; but in D: Nullable!int i; auto j = null; string k = null; writefln("%s", i.isNull); // I need to invoke Nullable property isNull; writefln("%s", i == null); // I can't just do this. writefln("%s", j == null); writefln("%s", k == null);
I hear you. IMO Nullable should be modified a bit to serve the purpose of turning non-nullable types in to nullable types and only that (right now it's confusing itself with an optional type). Then we could implement opEquals(typeof(null)) so that nullable == null would work. I.e. struct Nullable(T) { static if (isPointer!T) { private PointerTarget!T _value = PointerTarget!T.init; } else { private T _value = T.init; } bool opEquals(typeof(null)) { return isNull; } } Then Nullable!(int*) would be the same as int*. Or even better maybe is to give a compiler error when you try and stuff a nullable type inside a Nullable. Because ... why? Cheers, - Ali
Aug 27 2018
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 27 August 2018 at 19:36:29 UTC, aliak wrote:
 Then Nullable!(int*) would be the same as int*. Or even better 
 maybe is to give a compiler error when you try and stuff a 
 nullable type inside a Nullable. Because ... why?
Isn't it arguable, whether this is desired? I mean, in the present state you can separate the cases, whether the Nullable is set or not. This is a feature. If Nullable!(int*) behaves like int*, it would be somewhat more straight forward, which is maybe also a feature. But you loose something you can do right now...
Aug 27 2018
parent aliak <something something.com> writes:
On Monday, 27 August 2018 at 21:48:04 UTC, Alex wrote:
 On Monday, 27 August 2018 at 19:36:29 UTC, aliak wrote:
 Then Nullable!(int*) would be the same as int*. Or even better 
 maybe is to give a compiler error when you try and stuff a 
 nullable type inside a Nullable. Because ... why?
Isn't it arguable, whether this is desired? I mean, in the present state you can separate the cases, whether the Nullable is set or not. This is a feature. If Nullable!(int*) behaves like int*, it would be somewhat more straight forward, which is maybe also a feature. But you loose something you can do right now...
Certainly arguable :) I'm unsure about of what you lose is worth having, is the problem. And I have trouble thinking of a use case? If we implement opEquals(typeof(null)) as is now, then this code: Nullable!(int*) n = null; assert(n != null); passes. And if we have no opEquals then we can't test for native null on a 'null'able type O_o Another options is: bool opEquals(typeof(null)) { enum isNullInvalid = is(T == class) || is(T == interface) || isSomeFunction!T; static if (isNullInvalid) return isNull || data is null else return isNull; } I also did a quick search on google "allintext: "nullable" site:github.com filetype:d" and there were 0 instances of T* (just looked thorugh search results didn't click in).
Aug 27 2018
prev sibling parent vit <vit vit.vit> writes:
On Monday, 27 August 2018 at 12:54:59 UTC, SG wrote:
 On Monday, 27 August 2018 at 03:21:04 UTC, rikki cattermole 
 wrote:
 Templates make it the easiest way, since common patterns, like 
 arrays, classes and pointers have the exact same null check 
 syntax.
I see.

 value type. Which it would not work for.
Struct S{ public int? i; } S.i == null; // This works nicely.
 You don't need isNull function for Nullable because it has a 
 method called it. That will be preferred (hence I specifically 
 used isNull as the name).

 For Variant, use hasValue.

 bool isNull(Variant value) {
 	return !value.hasValue;
 }
The problem I'm trying to solve is beyond that. This is just an example. But bear with me, right now all I want is a function to check the value from 'a' type and return if it is null. The type could be a: Class, Struct, a Basic data type, Variant, Nullable and so. And what I see, these types has different behaviors, while in few lines to perform it, in D I found very hard. Isn't counter intuitive the way D works? Because for each type Class/Nullable you check with .isNull, for Variant with .hasValue, for string (variable is null). Thanks.
hasValue isn't equivalent of isNull or is null. 'null' is valid value in Variant: import std.variant; Variant v; v = null; assert(v.hasValue); //v has value assert(v.get!(typeof(null)) is null); //value in v is null Nullable!T.isNull isn't equivalent of is null: int* i = null; Nullable!(int*) ni; ni = i; assert(ni.isNull == false); ///ni has value assert(ni is null); ///ni value is null string is null isn't equivalent of empty: string str = "test"; str = str[0 .. 0]; assert(str !is null); ///str isn't null assert(str.empty); ///str is empty
Aug 27 2018