Current sentiment on Nullable.get

Rubn where at is.this
Fri Dec 14 22:34:56 UTC 2018


On Thursday, 13 December 2018 at 13:47:34 UTC, Jonathan M Davis 
wrote:
> On Thursday, December 13, 2018 4:41:01 AM MST aliak via 
> Digitalmars-d wrote:
>> On Tuesday, 11 December 2018 at 22:32:45 UTC, Jonathan M Davis
>>
>> wrote:
>> > Ultimately, allocation is the main difference here. Nullable 
>> > provides a way to emulate the behavior of a pointer with 
>> > regards to nullability without having to allocate on the 
>> > heap. An Optional or Maybe type is ultimately the same 
>> > thing, just with a different name. If it weren't for the 
>> > issue of heap allocation, it could easily argued that 
>> > pointers negate the need for any kind of 
>> > Nullable/Optional/Maybe type, because they provide that 
>> > functionality. And they don't even cause memory safety 
>> > issues if you're not doing pointer arithmetic. So, really, I 
>> > think that the need for heap allocation is _exactly_ the 
>> > issue here that these types are designed to solve and that 
>> > without that, a Nullable/Optional/Maybe type isn't adding 
>> > much.
>>
>> This is not the point of optional types. They're just there to 
>> denote if a value exists or not.
>
> Which you can do with a pointer. There is no need to have an 
> "optional" type if you don't care about heap allocations. If 
> you don't care about heap allocations, than you can just use T* 
> and not bother with creating a library type. It even works if 
> you already have a pointer, because you can have a pointer to a 
> pointer: T**. Having an optional/maybe type allows you to 
> indicate whether a value is present _without_ that extra heap 
> allocation. It gives you pointer semantics with regards to 
> whether a value is present without needing a pointer. So, 
> ultimately, avoiding a heap allocation is the reason that such 
> optional/maybe types exist, and it's why Nullable exists.
>
>> > At most, it's making it clear that it's expected that the 
>> > value can be null/empty/missing, because not all functions 
>> > that involve pointers consider null to be an acceptable 
>> > value.
>>
>> That makes a big difference. With everything. Writing the 
>> code, maintaining code, reviewing code, coming back to code, 
>> getting in to a language. Principle of least surprises. 
>> Intuitiveness. These all matter:
>>
>> class C {}
>> struct S {}
>>
>> * What is Nullable!(int*)? An int * that can be null? But 
>> wait...
>> * What is Nullable!C? A reference type that can be null? Isn't
>> that just "C" ? What is this adding? How does this make sense?
>> * What does this do: "Nullable!C a = null; a.isNull;"? if it's
>> false does that mean C exists? So C exists?
>> * What is Nullable!S? A struct that can be null or a struct 
>> that
>> may exist? Or was it just to avoid heap allocation?
>> * What's the difference between null and any of those other
>> types' isNull?
>> * Nullable!C a = null; a.get; // should that throw/assert?
>>
>> These are all non-obvious.
>
> The behavior is completely obvious if you understand that 
> whether a Nullable is null refers to the Nullable itself and 
> not the value that it contains. Looking at the documentation, 
> it does need to be improved so that that is clearer. But if you 
> understand that, then there is no confusion.
>
> And if you're not writing generic code, then the only reason to 
> even put a pointer or reference in a Nullable in the first 
> place is so that you can differentiate between a pointer or 
> reference that has been given a value rather than being simply 
> default-initialized. If you didn't care about that, then you 
> would just use the pointer or reference directly, because the 
> Nullable would do _nothing_ for you. It would be a pointless 
> wrapper.
>
> And if you're writing generic code, then having isNull act 
> differently for pointers than it does for value types would not 
> work at all, because you'd have to special-case the code to 
> handle the fact that assigning the Nullable a value could still 
> result in isNull being true in the case where the Nullable 
> contained a pointer or reference. So, the code would no longer 
> be generic. And if it wasn't going to be generic, then you'd 
> just use the naked pointer or reference rather than using a 
> Nullable. The entire reason that Nullable was changed to allow 
> types that are naturally nullable was so that generic code 
> could use Nullable without having to be special-cased for 
> pointers or references. That does come with the downside that 
> isNull might be confusing if you don't understand what Nullable 
> is, and the documentation clearly needs to be improved on that 
> front, but there's no problem there with how Nullable works. 
> It's just now a worse name, because it was changed to allow 
> types that are naturally nullable and that can therefore have 
> the value of null.
>
>> > IMHO, the only real naming issue that we have with Nullable 
>> > is that once it was changed to allow actual pointers 
>> > (whereas originally, it just contained types that could not 
>> > themselves be null), the property isNull became confusing to 
>> > some folks, because they thought that the null value of a 
>> > pointer and whether the Nullable itself was null were 
>> > related, when they're not (and if they were, it would cause 
>> > subtle bugs - especially in generic code).
>>
>> Yes, and this is just bad. Bad bad bad. How can any API that 
>> causes subtle bugs be something anyone would want to keep 
>> around??
>
> How on earth does Nullable cause subtle bugs? The only issue 
> with it that I see is that the fact that it's aliased to its 
> get member risks bugs when you change code that used a T to use 
> Nullable!T. Without that alias, you'd be forced to update the 
> code and make sure that it could handle when isNull was true, 
> whereas right now, it can be trivial to just change a 
> variable's type from T to Nullable!T and assume that it works, 
> and even if you're careful and try to make the code use get and 
> isNull properly, you can easily miss a place where the alias is 
> used and end up with a bug. But if the alias is removed like 
> the OP wants, then that entire problem goes away, and then I 
> don't see why Nullable would cause subtle bugs.
>
> I'll grant you that now that Nullable allows types which are 
> naturally nullable, the name is worse, because it does 
> sometimes cause confusion around isNull. But it's against 
> current policy to rename stuff in Phobos simply to give it a 
> better name, and if the documentation is improved, that problem 
> should largely go away. At that point, the only folks who would 
> be confused are those that don't read the docs, and folks who 
> don't read the documentation for the code they're reading or 
> maintaining are going to be confused in general. If we were to 
> start over, then yeah, it should probably be named Optional or 
> Maybe or whatever rather than Nullable given that it accepts 
> naturally nullable types, but I fail to see how its design 
> causes bugs aside from the problems caused by the alias. And we 
> should be able to fix that via deprecation, only breaking code 
> that arguably should be broken in the process, whereas renaming 
> stuff breaks _all_ code using Nullable, the vast majority of 
> which is perfectly fine - which is why Walter and Andrei are 
> against allowing renaming stuff. It breaks tons of code, and in 
> general, the benefit is highly subjective if not outright 
> negligible. It's probably worth more in this case than in many 
> other cases, but it would still involve breaking tons of 
> perfectly valid code.
>
> - Jonathan M Davis

https://github.com/dlang/phobos/commit/bfa6cd72ae83a977f272bf3520f3ef5da99eb7cf#diff-4e008aedb3026d4a84f58323e53bf017R1862

Had a good laugh when I found this. Looks like someone just 
didn't know what they were doing and someone was picking up their 
pieces.


More information about the Digitalmars-d mailing list