www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Nullable with reference types

reply "sigod" <sigod.mail gmail.com> writes:
Hi, everyone.

```
import std.typecons : Nullable;

class Test {}

Nullable!Test test;
assert(test.isNull);
```

Why does `Nullable` allowed to be used with reference types (e.g. 
classes)?

P.S. I have experience with C#, where `Nullable<T>` cannot be 
used with reference types. And it sounds logical to me.
Jun 29 2015
next sibling parent "Gary Willoughby" <dev nomad.so> writes:
On Monday, 29 June 2015 at 19:29:37 UTC, sigod wrote:
 Hi, everyone.

 ```
 import std.typecons : Nullable;

 class Test {}

 Nullable!Test test;
 assert(test.isNull);
 ```

 Why does `Nullable` allowed to be used with reference types 
 (e.g. classes)?

 P.S. I have experience with C#, where `Nullable<T>` cannot be 
 used with reference types. And it sounds logical to me.
It does feel wrong but there is another feature of Nullable where you can define the value of null. Which might be handy in some cases where you don't want a reference type to actually be null? I don't know if this is the case but it may be useful.
Jun 29 2015
prev sibling parent reply "Meta" <jared771 gmail.com> writes:
On Monday, 29 June 2015 at 19:29:37 UTC, sigod wrote:
 Hi, everyone.

 ```
 import std.typecons : Nullable;

 class Test {}

 Nullable!Test test;
 assert(test.isNull);
 ```

 Why does `Nullable` allowed to be used with reference types 
 (e.g. classes)?

 P.S. I have experience with C#, where `Nullable<T>` cannot be 
 used with reference types. And it sounds logical to me.
It's a design mistake in Nullable. I would suggest that either never use Nullable with a type that already has a null value, or use the "overload" of Nullable that takes a null value, and set it to null. Example: Class Test {} alias NullableTest = Nullable!(Test, null);
Jun 29 2015
next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Tuesday, 30 June 2015 at 00:02:38 UTC, Meta wrote:
 It's a design mistake in Nullable. I would suggest that either 
 never use Nullable with a type that already has a null value, 
 or use the "overload" of Nullable that takes a null value, and 
 set it to null. Example:

 Class Test {}
 alias NullableTest = Nullable!(Test, null);
Can we not specialize the other overload for references, pointers, and maybe slices?
Jun 30 2015
parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 30 June 2015 at 11:50:19 UTC, Marc Sch├╝tz wrote:
 On Tuesday, 30 June 2015 at 00:02:38 UTC, Meta wrote:
 It's a design mistake in Nullable. I would suggest that either 
 never use Nullable with a type that already has a null value, 
 or use the "overload" of Nullable that takes a null value, and 
 set it to null. Example:

 Class Test {}
 alias NullableTest = Nullable!(Test, null);
Can we not specialize the other overload for references, pointers, and maybe slices?
Not now, as that would break code relying on this behaviour. I've created a replacement for Nullable that does this, though, and it works quite well.
Jun 30 2015
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, 30 June 2015 at 00:02:38 UTC, Meta wrote:
 On Monday, 29 June 2015 at 19:29:37 UTC, sigod wrote:
 Hi, everyone.

 ```
 import std.typecons : Nullable;

 class Test {}

 Nullable!Test test;
 assert(test.isNull);
 ```

 Why does `Nullable` allowed to be used with reference types 
 (e.g. classes)?

 P.S. I have experience with C#, where `Nullable<T>` cannot be 
 used with reference types. And it sounds logical to me.
It's a design mistake in Nullable. I would suggest that either never use Nullable with a type that already has a null value, or use the "overload" of Nullable that takes a null value, and set it to null. Example: Class Test {} alias NullableTest = Nullable!(Test, null);
I tend to think that it's incredibly stupid to use something like Nullable for a type that's already Nullable. It's just silly. If a type is already nullable, then just use that and stop being adding extra overhead for no good reason. However, it _is_ true that if you need to have a nullable variable in generic code where the type that you need to be nullable could be any type, then having Nullable work with all types - and work with them all in the same way - is useful. Without that, you'd have to special case your code for types which were naturally nullable (and thus used null) and those which required Nullable. So, I can see why it could be useful to have Nullable work with classes, but I also question how common such a use case is. - Jonathan M Davis
Jun 30 2015
next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 30 June 2015 at 15:17:00 UTC, Jonathan M Davis wrote:
 I tend to think that it's incredibly stupid to use something 
 like Nullable for a type that's already Nullable.
Unfortunately, we're stuck with it as changing that would break code.
 It's just silly. If a type is already nullable, then just use 
 that and stop being adding extra overhead for no good reason.
I agree. There are several minuscule advantages you get from wrapping a nullable type with Nullable, but they're almost negligible.
Jun 30 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/30/15 11:16 AM, Jonathan M Davis wrote:
 On Tuesday, 30 June 2015 at 00:02:38 UTC, Meta wrote:
 On Monday, 29 June 2015 at 19:29:37 UTC, sigod wrote:
 Hi, everyone.

 ```
 import std.typecons : Nullable;

 class Test {}

 Nullable!Test test;
 assert(test.isNull);
 ```

 Why does `Nullable` allowed to be used with reference types (e.g.
 classes)?

 P.S. I have experience with C#, where `Nullable<T>` cannot be used
 with reference types. And it sounds logical to me.
It's a design mistake in Nullable. I would suggest that either never use Nullable with a type that already has a null value, or use the "overload" of Nullable that takes a null value, and set it to null. Example: Class Test {} alias NullableTest = Nullable!(Test, null);
I tend to think that it's incredibly stupid to use something like Nullable for a type that's already Nullable. It's just silly. If a type is already nullable, then just use that and stop being adding extra overhead for no good reason. However, it _is_ true that if you need to have a nullable variable in generic code where the type that you need to be nullable could be any type, then having Nullable work with all types - and work with them all in the same way - is useful. Without that, you'd have to special case your code for types which were naturally nullable (and thus used null) and those which required Nullable. So, I can see why it could be useful to have Nullable work with classes, but I also question how common such a use case is.
I know this is just back-of-envelope, but what's wrong with: alias Nullable(T) if(is(T == class)) = T; bool isNull(T)(T t) if(is(T == class)) { return t is null;} ? -Steve
Jun 30 2015
next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, June 30, 2015 14:29:52 Steven Schveighoffer via Digitalmars-d-learn
wrote:
 I know this is just back-of-envelope, but what's wrong with:

 alias Nullable(T) if(is(T == class)) = T;

 bool isNull(T)(T t) if(is(T == class)) { return t is null;}
In principle, there's no reason why we can'd do something like that. It's essentially what we do with the take and its return type (though that doesn't require a free function for additional functionality). The question would be whether it would break code to do so and whether it would be worth the breakage if we did. - Jonathan M Davis
Jul 01 2015
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Tuesday, 30 June 2015 at 18:29:31 UTC, Steven Schveighoffer 
wrote:
 I know this is just back-of-envelope, but what's wrong with:

 alias Nullable(T) if(is(T == class)) = T;

 bool isNull(T)(T t) if(is(T == class)) { return t is null;}
That's what I intended. (Same for pointers and slices, BTW.) I does however have a slightly different behaviour: In the current implementation, there can be instances for which `isNull` returns false, but whose payloads are nevertheless `null`.
Jul 01 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/1/15 5:45 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:
 On Tuesday, 30 June 2015 at 18:29:31 UTC, Steven Schveighoffer wrote:
 I know this is just back-of-envelope, but what's wrong with:

 alias Nullable(T) if(is(T == class)) = T;

 bool isNull(T)(T t) if(is(T == class)) { return t is null;}
That's what I intended. (Same for pointers and slices, BTW.) I does however have a slightly different behaviour: In the current implementation, there can be instances for which `isNull` returns false, but whose payloads are nevertheless `null`.
Oh. Sorry to say this, but that code is just broken. I frankly don't think we should concern ourselves with that use case. I wish I had paid more attention when this was all going down. -Steve
Jul 01 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/1/15 5:45 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:
 On Tuesday, 30 June 2015 at 18:29:31 UTC, Steven Schveighoffer wrote:
 I know this is just back-of-envelope, but what's wrong with:

 alias Nullable(T) if(is(T == class)) = T;

 bool isNull(T)(T t) if(is(T == class)) { return t is null;}
That's what I intended. (Same for pointers and slices, BTW.) I does however have a slightly different behaviour: In the current implementation, there can be instances for which `isNull` returns false, but whose payloads are nevertheless `null`.
I just realized this. With a Nullable!(T[]), you can have a type where: x is null x == null x.isNull all have different behavior. I'm really quite unconvinced that this has any good properties. I think we should fix it. -Steve
Jul 01 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, July 01, 2015 08:43:59 Steven Schveighoffer via
Digitalmars-d-learn wrote:
 On 7/1/15 5:45 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:
 On Tuesday, 30 June 2015 at 18:29:31 UTC, Steven Schveighoffer wrote:
 I know this is just back-of-envelope, but what's wrong with:

 alias Nullable(T) if(is(T == class)) = T;

 bool isNull(T)(T t) if(is(T == class)) { return t is null;}
That's what I intended. (Same for pointers and slices, BTW.) I does however have a slightly different behaviour: In the current implementation, there can be instances for which `isNull` returns false, but whose payloads are nevertheless `null`.
I just realized this. With a Nullable!(T[]), you can have a type where: x is null x == null x.isNull all have different behavior. I'm really quite unconvinced that this has any good properties. I think we should fix it.
It most definitely is _not_ good practice, and I would be fine with fixing it, but at the same time, I could see someone screaming about code breakage, though most likely, they'd simply end up triggering bugs in their code that were hidden by the current behavior. - Jonathan M Davis
Jul 01 2015