Current sentiment on Nullable.get

Jonathan M Davis newsgroup.d at
Sat Dec 15 01:33:28 UTC 2018

On Friday, December 14, 2018 4:39:16 PM MST Sebastiaan Koppe via 
Digitalmars-d wrote:
> On Thursday, 13 December 2018 at 13:14:13 UTC, Jonathan M Davis
> wrote:
> >> import std.typecons;
> >> class C {
> >> }
> >> void main() {
> >>
> >>      Nullable!C c;
> >>      assert(c.isNull);
> >>      c = null;
> >>      assert(!c.isNull);
> >>
> >> }
> >> ---
> >
> > I don't see anything wrong with that code. It's exactly how
> > it's supposed to work.
> It is confusing, it doesn't follow the principle of least
> astonishment.

Honestly, I have never found it counfusing, but I don't disagree that having
a different name would be less confusing for some folks. Regardless of the
naming though, Nullable has exactly the semantics that it needs to have to
make any sense to use it with naturally nullable types. If isNull cared
about the value of what the Nullable contained, pointers would not work the
same as other types inside a Nullable, making Nullable treacherous to use in
generic code, and if the code is not generic, and isNull just tells you
whether the pointer is null, then you might as well use the pointer

Using Nullable!(T*) can make sense in non-generic when you want to indicate
whether the variable has been assigned a value rather than being
default-initialized, and it makes sense in generic code where you don't care
what type you're operating on. But Nullable!(T*) makes no sense whatsoever
if isNull indicates anything about the pointer's value.

> In languages where nullable/optional/maybe is more central, you
> are advised to avoid calling get directly, and you are expected
> to always map or foreach over it.
> Essentially it is a range with 0 or 1 element.

I have never seen an Optional type that worked that way or worked with code
that did anything like that. That obviously does not mean that such code
doesn't exist, but personally, it strikes me as a bizarre way to operate,
and I've never written code that way. Having a type that contains zero or
more elements (such as a range) makes sense to me, but mapping that API onto
a type that can contain one or zero just seems bizarre to me. That being
said, it's pretty trivial for someone to write a function that operates on a
pointer or Nullable that way if that's what they want.

Either way, it would totally screw with code that does consider null to be
distinct from not having a value for Nullable to treat isNull as having
anything to do with the value of that's contained in the Nullable. e.g.
IIRC, when someone previously suggested making such a change to Nullable, it
was pointed out that it would break vibe.d, because it has code that uses
Nullable!(T*) with null having a distinct meaning separate from the Nullable
having no value.

> > Nullable is often used simply to denote whether the variable
> > has been given a value yet
> Do you consider null a value? Because Nullable does.

Whether null is a valid value depends entirely on how the code works.
Putting a pointer inside a Nullable is essentially the same as having a
pointer to a pointer. T** is nullable, but whether the outer pointer is null
says nothing about whether the T* it points to is null. Some code would
consider having the T* pointed to by the T** as null to be a perfectly valid
value, whereas other code would not.

And if you want to indicate whether a variable has been given a value or not
when the init value for that type is a valid value, then you pretty much
have to use either a pointer to that value or something like Nullable which
uses a separate bool to indicate whether variable has been given a value.

- Jonathan M Davis

More information about the Digitalmars-d mailing list