In C#2+ there's the Nullable type, one of its main purposes is to represent
null values coming from databases. Another purpose for D is for example
find(iterable) can return a Nullable!T instead of throwing an exception (or
returning -1) if no item can be found. So if seen as useful D can add a
Nullable to Phobos in less than two years from now, when dmd2 has less bugs.
A Nullable struct is not so complex, it can be added to Phobos2. Before
creating it some design decisions are necessary, here are three of them:
1) Nullable!(SomeClass) is forbidden in C#. D Nullable can do the same, but
this hurts generic code a little. An alternative is in this case to not add the
boolean field to the Nullable and make hasValue just look if the reference !is
null (so if T is a class then (Nullable!T).sizeof == T.sizeof). If object
references are allowed then writing the value field sets the hasValue boolean
to true if T is not a class reference.
2) C# forbids Nullable!(Nullable!T), D can do the same or it can make
Nullable!(Nullable!T) === Nullable!T to allow to write simpler generic code.
3) C# uses something similar to valueorInit() that returns T.init if the
hasValue property is false. D can do the same, or it can use
get(default=T.init) that returns the value if present or the given default (or
the default default). This can be a problem if a delegate is taken out of get
because in D default values are added at call point, they are not an
information stored inside the callee as in Python.
So Nullable can have the methods/properties:
value
property hasValue
get(defaukt=T.init)
type alias of T
Reading the value if hasValue is false generates a specific exception.
An error for safety:
Nullable!int x;
int y = x; // compile ERROR
int y = x.get(); // OK
int y = x.get(5); // OK
int y = x.hasValue ? x.value : x.type.init; // OK
int y = x.hasValue ? x.value : -1; // OK
Optionally this can be accepted:
Nullable!int x;
if (x) { ...
that is equivalent to:
if (x.hasValue) { ...
But this doesn't look fully tidy to me...
---------------
So far I think Nullable can be implemented with not changes in the
language/compiler. Now some small things that can require such changes.
C# has the ?? operator (Elvis operator) that can be used to replace this:
Nullable!int x;
int y = x.hasValue ? x.value : -1; // OK
With:
Nullable!int x;
int y = x ?? -1;
In C# there is a bit of syntax sugar for:
Nullable!int x;
that can be written:
int? x;
This can be done in D too, but this can be added later too. The advantage of
this syntax sugar is to encourage programmers to use Nullables.
There is another possible bit of compiler help, to avoid most of those empty
Nullable exceptions and make Nullable a bit safer the compiler can refuse code
like:
Nullable!int result = foo();
int x = result.value;
And accept code like:
Nullable!int result = foo();
if (result.hasValue) {
int x = result.value;
...
} else {
...
}
Bye,
bearophile

I figure a Nullable struct would just alias the original type if T t;
t = null; already compiles. So a nullable pointer, class, or Nullable
is just a no-op. This would cover your cases 1 and 2 with a simple
rule.

Optionally this can be accepted:
Nullable!int x;
if (x) { ...
that is equivalent to:
if (x.hasValue) { ...
But this doesn't look fully tidy to me...

C# has the ?? operator (Elvis operator) that can be used to replace this:
int y = x ?? -1;

Meh, the regular ternary works fine, or this could be a member function:
x.get(-1); // gets if not null, returns -1 if it is null
x itself is a struct, so it can never be null, so no need to worry
about x.get throwing a segfault.

This can be done in D too, but this can be added later too. The advantage of
this syntax sugar is to encourage programmers to use Nullables.

Gah, Nullable!T is perfectly fine. I don't even know if you actually
want to encourage people to use nullables; they shouldn't be needed
all that often says my gut. Better to avoid things being null if
possible.

I figure a Nullable struct would just alias the original type if T t;
t = null; already compiles. So a nullable pointer, class, or Nullable
is just a no-op. This would cover your cases 1 and 2 with a simple
rule.

I don't think that's a good idea, you lose the standard API of Nullable, so
it's worse than useless.
Two better solutions are the one chosen by C# (refuse object references as T)
or accept them too (and don't add a boolean after the T, using the null
reference to store the missing T).
Bye,
bearophile

Strange... I could have sworn that when I recently tried D2, arrays
supported range methods (popFront etc), and that those were implemented in
std.array. Am I mistaken, or how does that work?

Arrays work for it, and have for quite a while, but nothing else does
yet; it doesn't work with classes and pointers, which are the other
important built-in nullables.

Now that you mention it, yes, that sounds familiar.
That brings up an interesting corner case though: once uniform call syntax is
supported for pointers and references, and you have a null reference x, an
actual method x.foo() would give you a segmentation fault, while a pseudomethod
that is implemented as a free function could have the same call syntax,
x.foo(), but could potentially work even for null references. Correct?
Not saying it's necessarily a problem, just slightly unexpected.

Then went off and implemented something where that doesn't actually
compile, and forgot to mention it.
This is the reason I used a T* in the nullable struct; I was hoping to
take T* is null and make it work for the struct as a whole, but it
didn't work. (tried alias this).
But I dropped it and got everything else to work, so it isn't all bad,
I just forgot to mention this.
It would still be nice if x is null could be gotten to work here. It
wouldn't feel complete without it.

I don't think that's a good idea, you lose the standard API of Nullable,
so
it's worse than useless.

Make that standard API free functions, like std.array does. Then, it
would work with all nullable items, and not just Nullable ones.
Uniformity is good.

But ducks are bad. How about an INullable that's implemented by Nullable and
implicitly implemented by classes? (That's one thing I like about C# - it
uses nice safe explicit interfaces instead of compile-time duck-typing.)

Oh, I don't know. You don't want to over do it, but to me a nullable
thing is just anything where item = null; compiles; a good fit for a
duck.

How about an INullable that's implemented by Nullable and
implicitly implemented by classes?

A problem here is if the class is null, you won't be able to use it. Consider:
interface INullable {
bool isNull();
}
class Whatever : INullable {
bool isNull() { return this is null; }
}
void main() {
Whatever a;
if(a.isNull()) // hardware exception, since this is null, it
can't get at the interface
}

(That's one thing I like about C# - it
uses nice safe explicit interfaces instead of compile-time duck-typing.)

Yea, there is a nice benefit there, but in this specific case, I don't
think it can be done due to the nature of null.

That brings up an interesting corner case though: once uniform call syntax
is supported for pointers and references, and you have a null reference x,
an actual method x.foo() would give you a segmentation fault, while a
pseudomethod that is implemented as a free function could have the same call
syntax, x.foo(), but could potentially work even for null references.
Correct?

Yes, that would work. It is necessary that it does for a nullable api
too, since hasValue should be a call, which is the same as !is null;
it needs to be able to return false if it is null, not segfault.
(Ideally, I'd just like to get the "x is null" to work somehow, but
however it looks, it does need to work.)