www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to check if variable of some type can be of null value?

reply Alexey <invalid email.address> writes:
I've tried to use ```typeof(t) is cast(t)null```, but compiler 
exits with error and so this can't be used for checking this 
issue.

The goal I with to achieve by this check - is to use template and 
to assign value to variable basing on it's ability to accept null 
as a value.

some testing code below.

```D
import std.stdio;

interface I1
{
}

class C1 : I1
{
}

struct S1
{
}

struct S2
{
     int a=1;
}

void main()
{

     auto c1 = new C1;

     I1 i1 = c1;

     auto s1 = S1();
     auto s2 = S2();

     static assert(typeof(c1).init is cast(typeof(c1)) null);
     static assert(typeof(i1).init is cast(typeof(i1)) null);
     static assert(typeof(s1).init is cast(typeof(s1)) null);
     static assert(typeof(s2).init is cast(typeof(s2)) null);
     static assert(int.init is cast(int) null);

}

```
Jul 24 2021
next sibling parent reply Alexey <invalid email.address> writes:
On Saturday, 24 July 2021 at 18:10:07 UTC, Alexey wrote:
 I've tried to use ```typeof(t) is cast(t)null```, but compiler 
 exits with error and so this can't be used for checking this 
 issue.

 The goal I with to achieve by this check - is to use template 
 and to assign value to variable basing on it's ability to 
 accept null as a value.
currently I ended up using ```__traits(compiles, cast(T1)null)``` for this check. but don't know is this really semantically correct.
Jul 24 2021
parent reply JG <JG somewhere.com> writes:
On Saturday, 24 July 2021 at 19:39:02 UTC, Alexey wrote:
 On Saturday, 24 July 2021 at 18:10:07 UTC, Alexey wrote:
 I've tried to use ```typeof(t) is cast(t)null```, but compiler 
 exits with error and so this can't be used for checking this 
 issue.

 The goal I with to achieve by this check - is to use template 
 and to assign value to variable basing on it's ability to 
 accept null as a value.
currently I ended up using ```__traits(compiles, cast(T1)null)``` for this check. but don't know is this really semantically correct.
There are probably better ways. However, this seems to work: ```d import std; enum canBeSetToNull(T) = __traits(compiles,(T.init is null)); interface I1 { } class C1 : I1 { } struct S1 { } struct S2 { int a=1; } void main() { auto c1 = new C1; I1 i1 = c1; auto s1 = S1(); auto s2 = S2(); static assert(canBeSetToNull!(typeof(c1))); static assert(canBeSetToNull!(typeof(i1))); static assert(!canBeSetToNull!(typeof(s1))); static assert(!canBeSetToNull!(typeof(s2))); static assert(!canBeSetToNull!(int)); static assert(canBeSetToNull!(int*)); }```
Jul 24 2021
parent JG <JG somewhere.com> writes:
On Saturday, 24 July 2021 at 20:10:37 UTC, JG wrote:
 On Saturday, 24 July 2021 at 19:39:02 UTC, Alexey wrote:
 [...]
There are probably better ways. However, this seems to work: ```d import std; enum canBeSetToNull(T) = __traits(compiles,(T.init is null)); interface I1 { } class C1 : I1 { } struct S1 { } struct S2 { int a=1; } void main() { auto c1 = new C1; I1 i1 = c1; auto s1 = S1(); auto s2 = S2(); static assert(canBeSetToNull!(typeof(c1))); static assert(canBeSetToNull!(typeof(i1))); static assert(!canBeSetToNull!(typeof(s1))); static assert(!canBeSetToNull!(typeof(s2))); static assert(!canBeSetToNull!(int)); static assert(canBeSetToNull!(int*)); }```
Sorry, I see that is basically what you had.
Jul 24 2021
prev sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 24 July 2021 at 18:10:07 UTC, Alexey wrote:
 The goal I with to achieve by this check - is to use template 
 and to assign value to variable basing on it's ability to 
 accept null as a value.
The most direct representation of that is __traits(compiles, (T t) { t = null; }); Another cool trick to consider is: is(typeof(null) : Whatever) What that means is if the null literal will implicitly convert to Whatever type. This means you can pass `null` as an argument to a function accepting Whatever. Thus it includes pointers, classes, interfaces, arrays. But does NOT include structs, even if they have a null accepting constructor / opAssign since you still must explicitly construct them. struct S { void opAssign(typeof(null) n) {} } void main() { S s; s = null; // allowed due to opAssign } pragma(msg, is(typeof(null) : S)); // FALSE because this check only looks for implicit conversion, not user-defined assign overloads or constructors. The traits compiles check will allow this, since it is looking at assign... but the traits compiles will say false if it gets a `const` type since obviously then assign is not allowed, even if implicit conversion would be. Depending on your needs you might use one of these, or perhaps both.
Jul 25 2021