digitalmars.D.learn - Nullable!T with T of class type
- kdevel (25/25) Jun 25 2018 Just stumbled over the following design:
- Jonathan M Davis (34/50) Jun 25 2018 If you have a function that accepts Nullable!T, when that function is
- Nathan S. (4/8) Jun 26 2018 Java can be somewhat clever about this though. Often it just
- kdevel (6/18) Jun 26 2018 That was not the error. The error was that I used is null instead
- Jonathan M Davis (13/30) Jun 26 2018 Well, get checks whether the Nullable isNull, and throws an Error if it ...
- kdevel (2/4) Jun 28 2018 How do you signify that a struct member of class type is optional?
- Jonathan M Davis (10/14) Jun 28 2018 Structs aren't nullable, so wrapping them in a Nullable makes perfect se...
- kdevel (13/17) Jun 28 2018 It is already technically nullable. But how do you signify to the
- Jonathan M Davis (34/49) Jun 28 2018 That's something that you have to worry about with all code involving
- Jordan Wilson (7/27) Jun 28 2018 Reading inpput from a csv file, and the value could either be
- aliak (26/32) Jun 28 2018 So there're no optional type in D (ala Swift, Kotlin, Scala,
- Nathan S. (19/23) Jun 26 2018 Yes: https://run.dlang.io/is/hPxbyf
- kdevel (3/12) Jun 26 2018 Works nicely. Thanks!
Just stumbled over the following design: class S {...} class R { : Nullable!S s; : } s was checked in code like R r; : if (r.s is null) throw new Exception ("some error message"); At runtime the following was caught: fatal error: caught Throwable: Called `get' on null Nullable!S Why can't this programming error be detected at compile time? Is it possible to "lower" the Nullable operations if T is a class type such that there is only one level of nullification? BTW: https://dlang.org/library/std/typecons/nullable.html contains duplicate sections: Function nullable Function nullable Struct Nullable Struct Nullable
Jun 25 2018
On Monday, June 25, 2018 19:40:30 kdevel via Digitalmars-d-learn wrote:Just stumbled over the following design: class S {...} class R { Nullable!S s; } s was checked in code like R r; if (r.s is null) throw new Exception ("some error message"); At runtime the following was caught: fatal error: caught Throwable: Called `get' on null Nullable!S Why can't this programming error be detected at compile time?If you have a function that accepts Nullable!T, when that function is called, how on earth is it going to know whether the argument it received was null at compile time? That depends entirely on the argument, which could have come from anywhere. So, in the general case, the compiler can't possibly determine whether a variable is null or not at compile time. And as far as just within a function goes, Nullable is a library type. There's nothing special about it. The compiler has no magic knowledge about what it does or how it functions. So, how would it know that R r; r.foo(); was bad code? And honestly, this sort of problem actually gets surprisingly thorny even if you tried to bake this into the compiler for a built-in type. Sure, it would be straightforward for the compiler to see that int* i; *i = 42; is dereferencing null, but as soon as you start adding if statements, function calls, etc. it quickly becomes impossible for the compiler to accurately determine whether the pointer is null or not. Any such attempt will inevitably end up with false positives, forcing you to do stuff like assign variables values when you know that it's unnecessary - it would complicate the compiler considerably to even make the attempt. It's far simpler to just treat it as a runtime error. Even more restricted languages such as Java do that. Java does try to force you to initialize stuff (resulting in annoying false positives at times), but in general, it still can't guarantee when a variable is null or not and is forced to insert runtime null checks.Is it possible to "lower" the Nullable operations if T is a class type such that there is only one level of nullification?It's been discussed before, but doing so would make the behavior of Nullable depend subtly on what type it contained and risks bugs in generic code. Also, there _is_ code out there which depends on the fact that you can have a Nullable!MyClass where the variable has a value and that value is a null reference. If you really don't want the extra bool, then just don't use Nullable. Class references are already naturally nullable. - Jonathan M Davis
Jun 25 2018
On Monday, 25 June 2018 at 22:58:41 UTC, Jonathan M Davis wrote:Java does try to force you to initialize stuff (resulting in annoying false positives at times), but in general, it still can't guarantee when a variable is null or not and is forced to insert runtime null checks.Java can be somewhat clever about this though. Often it just needs to perform a single null check in a method body and thereafter knows the pointer can't be null and elides the check.
Jun 26 2018
On Monday, 25 June 2018 at 22:58:41 UTC, Jonathan M Davis wrote:On Monday, June 25, 2018 19:40:30 kdevel via Digitalmars-d-learn wrote:[...]R r; if (r.s is null) throw new Exception ("some error message");That was not the error. The error was that I used is null instead of .isNull() which lead to a different Exception (Error). [...]Why can't this programming error be detected at compile time?If you have a function that accepts Nullable!T, when that function is called, how on earth is it going to know whether the argument it received was null at compile time?If you really don't want the extra bool, then just don't use Nullable. Class references are already naturally nullable.Sure.
Jun 26 2018
On Tuesday, June 26, 2018 19:03:20 kdevel via Digitalmars-d-learn wrote:On Monday, 25 June 2018 at 22:58:41 UTC, Jonathan M Davis wrote:Well, get checks whether the Nullable isNull, and throws an Error if it is, which is what you showed in your original post. If you want a Nullable to have the value of null, then you have to explicitly set it to null. Nullable really doesn't have anything to do with the null value for pointers or references beyond the fact that it allows a way to emulate that behavior for non-nullable types by using a bool. isNull returns whether the Nullable has been given a value or not, whereas checking the value with is null means checking whether it has a value and whether that value is null. If that behavior is not what you want, then you will have to find a different solution, though honestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code. - Jonathan M DavisOn Monday, June 25, 2018 19:40:30 kdevel via Digitalmars-d-learn wrote:[...]R r; if (r.s is null) throw new Exception ("some error message");That was not the error. The error was that I used is null instead of .isNull() which lead to a different Exception (Error).Why can't this programming error be detected at compile time?If you have a function that accepts Nullable!T, when that function is called, how on earth is it going to know whether the argument it received was null at compile time?
Jun 26 2018
On Tuesday, 26 June 2018 at 21:54:49 UTC, Jonathan M Davis wrote:[H]onestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code.How do you signify that a struct member of class type is optional?
Jun 28 2018
On Thursday, June 28, 2018 18:10:07 kdevel via Digitalmars-d-learn wrote:On Tuesday, 26 June 2018 at 21:54:49 UTC, Jonathan M Davis wrote:Structs aren't nullable, so wrapping them in a Nullable makes perfect sense. Whether they happen to be on the stack or members of another type is irrelevant to that. It's wrapping types like pointers and class references in a Nullable that's an odd thing to do - the types where someone might ask why the extra bool is necessary in the Nullable. Wrapping them in a Nullable makes sense in generic code, because the code isn't written specifically for them, but something like Nullable!MyClass in non-generic code is pointless IMHO, because a class reference is already nullable. - Jonathan M Davis[H]onestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code.How do you signify that a struct member of class type is optional?
Jun 28 2018
On Thursday, 28 June 2018 at 19:22:38 UTC, Jonathan M Davis wrote:Nullable makes sense in generic code, because the code isn't written specifically for them, but something like Nullable!MyClass in non-generic code is pointless IMHO, because a class reference is already nullable.It is already technically nullable. But how do you signify to the reader of the code that a class member in a struct or in a class may intentionally (not purely technically) be null? If I had written class R { : S s; : } with S being a class. The reader of the code cannot spot if s is optional. In my code I could not have declared S as a struct since it implements an interface.
Jun 28 2018
On Thursday, June 28, 2018 19:45:52 kdevel via Digitalmars-d-learn wrote:On Thursday, 28 June 2018 at 19:22:38 UTC, Jonathan M Davis wrote:That's something that you have to worry about with all code involving classes. Putting Nullable on a class reference does seem like it would make it clear that you want it to be nullable, but it doesn't really, and the lack of nullable doesn't mean that it can't purposefully be null. If Nullable couldn't contain a null, or it didn't have a separate bool for null, then maybe it would help clarify, but that would result in subtle bugs in generic code whenever null is involved, and there are cases where code purposefully uses Nullable to indicate that the variable has not been initialized yet but where null is considered a reasonable value for the type. So, the fact that Nullable is there doesn't really clarify matters. It just opens up the question of what happens with null. In my experience, it's usually pretty clear from the API or design of a piece of code whether it's intended to accept null or not (usually, the answer is no) and that folks document what happens if null is provided if it's supposed to be accepted, but regardless, any case where it's not clear needs to be documented so that it is clear. Certainly, relying on Nullable for that is going to be error-prone, because Nullable allows null and can take advantage of the fact that isNull has nothing to do with the value of null. So, if the intention is that a Nullable!MyClass never have a value of null, then that needs to be documented, essentially defeating the purpose of putting it in a Nullable in the first place. At that point, it would just be more user-friendly to let it be null and document it as such than to use Nullable and require that someone provide an uninitialized or cleared Nullable instead of just using null. Now, some folks do use Nullable to try and handle whether a class reference is null, but given that it doesn't really solve the problem of what happens with null and still requires documenting the intent, I think that it's more misleading than enlightening to use Nullable on class references. If you're going to wrap class references to try and indicate whether they can be null or not, it makes far more sense to wrap a class reference in a wrapper intended to indicate that it _can't_ be null than one that's intended to indicate that it can be. - Jonathan M DavisNullable makes sense in generic code, because the code isn't written specifically for them, but something like Nullable!MyClass in non-generic code is pointless IMHO, because a class reference is already nullable.It is already technically nullable. But how do you signify to the reader of the code that a class member in a struct or in a class may intentionally (not purely technically) be null? If I had written class R { S s; } with S being a class. The reader of the code cannot spot if s is optional. In my code I could not have declared S as a struct since it implements an interface.
Jun 28 2018
On Thursday, 28 June 2018 at 19:22:38 UTC, Jonathan M Davis wrote:On Thursday, June 28, 2018 18:10:07 kdevel via Digitalmars-d-learn wrote:Reading inpput from a csv file, and the value could either be blank, na, or numeric. Nullable!MyClass could be used to represent 3 states in your programming logic. I'm not saying this is the best way to represent ternary states, but it's not unreasonable. Jordan WilsonOn Tuesday, 26 June 2018 at 21:54:49 UTC, Jonathan M Davis wrote:Structs aren't nullable, so wrapping them in a Nullable makes perfect sense. Whether they happen to be on the stack or members of another type is irrelevant to that. It's wrapping types like pointers and class references in a Nullable that's an odd thing to do - the types where someone might ask why the extra bool is necessary in the Nullable. Wrapping them in a Nullable makes sense in generic code, because the code isn't written specifically for them, but something like Nullable!MyClass in non-generic code is pointless IMHO, because a class reference is already nullable. - Jonathan M Davis[H]onestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code.How do you signify that a struct member of class type is optional?
Jun 28 2018
On Thursday, 28 June 2018 at 18:10:07 UTC, kdevel wrote:On Tuesday, 26 June 2018 at 21:54:49 UTC, Jonathan M Davis wrote:So there're no optional type in D (ala Swift, Kotlin, Scala, etc). There are a number of workarounds you can use to achieve the same type of behavior. You can use ranges to denote "some" value or no value (empty range). But it's a bit inconvenient and the APIs to get that running say nothing about intent. You can create a lightweight Maybe type: https://stackoverflow.com/questions/27241908/maybe-types-in-d I've implemented an optional type as well that includes safe dispatching, but it's not nogc right now -> https://github.com/aliak00/optional I think there's another optional type on dub somewhere as well. But using Nullable!T just defers the problem that optional solves: if (nullable.isNull) { nullable.get.doSomething(); } vs: if (ptr !is null) { ptr.doSomething(); } meh... It's more of a tool to allow you to give any type nullability semantics. Cheers, - Ali[H]onestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code.How do you signify that a struct member of class type is optional?
Jun 28 2018
On Monday, 25 June 2018 at 19:40:30 UTC, kdevel wrote:Is it possible to "lower" the Nullable operations if T is a class type such that there is only one level of nullification?Yes: https://run.dlang.io/is/hPxbyf ---- template Nullable(S) { import std.traits : isPointer, isDynamicArray; static if (is(S == class) || is(S == interface) || is(S == function) || is(S == delegate) || isPointer!S || isDynamicArray!S) { alias Nullable = S; } else { static import std.typecons; alias Nullable = std.typecons.Nullable!S; } } ----
Jun 26 2018
On Tuesday, 26 June 2018 at 14:32:59 UTC, Nathan S. wrote:On Monday, 25 June 2018 at 19:40:30 UTC, kdevel wrote:[...]Is it possible to "lower" the Nullable operations if T is a class type such that there is only one level of nullification?Yes: https://run.dlang.io/is/hPxbyf ---- template Nullable(S)----Works nicely. Thanks!
Jun 26 2018