Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-enable std.typecons.Nullable and NullableRef #153

Merged
merged 3 commits into from Aug 14, 2011
Merged

Re-enable std.typecons.Nullable and NullableRef #153

merged 3 commits into from Aug 14, 2011

Conversation

kennytm
Copy link
Contributor

@kennytm kennytm commented Jul 22, 2011

Re-enable these types which were disabled in commit d218c12 2 years ago.

These changes were made:

  1. Nullable!T.nullify calls object.clear instead of the destructor directly.
  2. Added @property and const annotations to isNull and get.
  3. Added a lot of unit tests to ensure 100% coverage.

@@ -1109,8 +1109,6 @@ unittest
assert(y == 5);
}

/+

/**
Defines a value paired with a distinctive "null" state that denotes
the absence of a valud value. If default constructed, a $(D
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're messing with this, you might as well fix the spelling in the description.

@jmdavis
Copy link
Member

jmdavis commented Jul 25, 2011

It looks fine from what I can see, but honestly, I don't quite get the point of Nullable in the first place. The typical way to solve the problem that it appears to be solving is to just use a pointer. Why add a whole new type for it? So that the value is on the stack instead of the heap?

@kennytm
Copy link
Contributor Author

kennytm commented Jul 25, 2011

@jmdavis: Mainly to add an invalid value to types which doesn't have it, and can be connected back to the original type. For example, I use this as Nullable!Endian when the endianness cannot be determined.

@jmdavis
Copy link
Member

jmdavis commented Jul 25, 2011

But pointers do that. You'd just use Endian*. If it doesn't have a value, then it's null. If it does, then it points to a value.

@alexrp
Copy link
Member

alexrp commented Jul 30, 2011

But that would imply using pointers in the first place; this might not be desirable for a variety of safety reasons, or for API simplicity. Also, Nullable explicitly communicates that the value may or may not be there; a pointer doesn't necessarily do this unless documented.

@jmdavis
Copy link
Member

jmdavis commented Aug 3, 2011

Nullable doesn't say anything more about a variable being able to be null than a pointer does. Both of them have the possibility of being null and both of them could have sections of code where it's assumed that they're not null. This adds nothing over pointers with regards to clarity IMHO.

Now, the fact that it's putting stuff on the stack could be valuable. It helps avoid heap allocations and could allow for the deterministic destruction of structs which would otherwise be on the heap (though hopefully the fact that structs' destructors aren't called if they're on the heap is only a temporary implementation issue rather than a permanent issue in the language). So, this may very well be of value for performance purposes, but I don't think that it adds anything over pointers if all you're looking for is the ability to make a type nullable.

It would be nice to hear more opinions on the value or lack thereof of Nullable however - particularly from others on the Phobos dev team.

@jpf91
Copy link
Contributor

jpf91 commented Aug 9, 2011

I guess Nullable could work in safeD, but pointers can't? That seems to be the biggest Nullable advantage to me. It also is safer: If you wrote functions to accept pointers, users could pass pointers to stack allocated memory which could go out of scope, etc.

@alexrp
Copy link
Member

alexrp commented Aug 9, 2011

Nullable doesn't say anything more about a variable being able to be null than a pointer does. Both of them have the possibility of being null and both of them could have sections of code where it's assumed that they're not null. This adds nothing over pointers with regards to clarity IMHO.

What I mean is, a Nullable!T clearly says "this value can correctly be null", while a pointer doesn't say whether or not it's allowed to be null, unless documented or assert'd or whatever.

@jmdavis
Copy link
Member

jmdavis commented Aug 9, 2011

@XTZGZoRex

And my point was that the there is no difference between Nullable!T and T* in that regard. Either of them could be allowed to be null or not allowed to be null in a particular situation. Just because a variable is Nullable!T doesn't mean that it's at all correct for it to be null. True, it's likely that it was correct for it to be null at some point in its lifetime, or it would T instead of Nullable!T, but that doesn't mean that it's valid for it to be null for every function that operates on it. Functions could easily assume that it isn't null depending on what they're doing and what the variable is used for. The same goes for a pointer.

So, as far as nullability goes and what you can assume about it, I see zero difference between Nullable!T and a T*.

@jmdavis
Copy link
Member

jmdavis commented Aug 9, 2011

@jpf91

Some very good points in favor of Nullable.

@jmdavis
Copy link
Member

jmdavis commented Aug 9, 2011

Though actually, pointers can be used in SafeD. It's pointer arithmetic which can't be, so that wouldn't affect this use case. The escaping referenc issue would though.

@kennytm
Copy link
Contributor Author

kennytm commented Aug 9, 2011

One difference of the nullable type over pointers outside of D is that they have a special equality semantic:

a == b   <=>    a is null && b is null 
             || a !is null && b !is null && a.value == b.value

This is seen in .NET framework's Nullable(T), Haskell's Data.Maybe and C++ (Boost)'s optional<T>.

However, Andrei's original code doesn't have this, e.g.

void main() {
    Nullable!int a;
    auto b = Nullable!int(4);
    assert(a != b); // object.Exception@/usr/include/phobos/std/typecons.d(1177): Enforcement failed
}

Does this worth the addition if this special opEquals is defined? (That require bug 3659 be fixed to work perfectly, though.)

(There are also other methods like C#'s GetValueOrDefault / Haskell's fromMaybe / Boost's get_value_or)

@jmdavis
Copy link
Member

jmdavis commented Aug 14, 2011

All things considered, this probably is worth adding to Phobos / uncommenting out. If nothing else, the fact that it's on the stack will be of definite value to those trying to avoid the heap as much as possible.

As for opEquals, I'm inclined to agree with the current behavior (throwing if you compare with one which isNull). However, I can see a definite argument for the .NET behavior.

@andralex
Copy link
Member

Yah, I, too, think this is worth adding. The difference between Nullable!T and T* is that the former encapsulates an optional value whereas the latter is a proxy for an optional value that exists elsewhere. The distinction may not seem too strong considering that "new T" is a limitless factory of Ts, but when we consider the performance implications this is worth having.

andralex added a commit that referenced this pull request Aug 14, 2011
Re-enable std.typecons.Nullable and NullableRef
@andralex andralex merged commit 7842390 into dlang:master Aug 14, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants