December 10, 2018
On Mon, Dec 10, 2018 at 10:43:40AM -0700, Jonathan M Davis via Digitalmars-d wrote: [...]
> However, IIRC, someone already tried to deprecate the alias and ran into a compiler bug that prevented it - though unfortunately, I can't find the bug report at the moment. I recall it being an issue with getting deprecation messages from the alias even when it wasn't used explicitly, but when I try a simple test case, I get a different bug entirely. This code snippet
> 
> struct S
> {
>     int get()
>     {
>         return 42;
>     }
> 
>     deprecated alias get this;
> }
> 
> void main()
> {
>     S s;
>     int i = s;
> }
> 
> doesn't result in any deprecation messages at all. Based on that, without some compiler fixes, it's not actually possible to deprecate the alias.
[...]

Hmm. I wonder if a circumlocution similar to the following might work?

	struct S
	{
		int get() { return 42; }
		deprecated int deprecatedGet() { return get(); }
		alias deprecatedGet this;
	}

The resulting error message leaves a lot to be desired, though.


T

-- 
"Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
December 10, 2018
On 2018-12-10 16:47, aliak wrote:

> Sounds like a step forward, deprecating that.
>
> Do people consider Nullable a type of Optional thing in general?

No, it's not the same as Optional.

> I have  a written a bit more details here [0] but basically I don't think
> deprecating .get is enough to make it "safe" - granted - depending on
> what safe means. In the context of D a segfault is safe so maybe that's
> ok. But then deprecating get doesn't add safety in that context anyway.

"get" has a few use cases, i.e. when you need to explicitly check if the value is present or not. Then, if it is present, you can use "get" to minimize overhead. But it's rare to need it.

-- 
/Jacob Carlborg
December 10, 2018
On 2018-12-10 18:07, jmh530 wrote:

> Does it make sense to deprecate Nullable as a whole, rather than just
> that piece?

Yes.

-- 
/Jacob Carlborg
December 11, 2018
On Monday, 10 December 2018 at 17:43:40 UTC, Jonathan M Davis wrote:
> However, IIRC, someone already tried to deprecate the alias and ran into a compiler bug that prevented it - though unfortunately, I can't find the bug report at the moment. I recall it being an issue with getting deprecation messages from the alias even when it wasn't used explicitly, but when I try a simple test case, I get a different bug entirely. This code snippet
>
> struct S
> {
>     int get()
>     {
>         return 42;
>     }
>
>     deprecated alias get this;
> }
>
> void main()
> {
>     S s;
>     int i = s;
> }
>
> doesn't result in any deprecation messages at all. Based on that, without some compiler fixes, it's not actually possible to deprecate the alias.
>
> - Jonathan M Davis

Deprecating get() works, for what it's worth. So the way to go would be changing Nullable to alias deprecated_get_ this;
December 11, 2018
On Monday, 10 December 2018 at 17:07:10 UTC, jmh530 wrote:
> On Monday, 10 December 2018 at 15:47:53 UTC, aliak wrote:
>> [...]
>
> Does it make sense to deprecate Nullable as a whole, rather than just that piece? Why would I use Nullable when I can use your optional library?

I would be all for that. I guess the only reason would be to have pointer semantics for value types 🤷‍♂️And I'm not really sure why you'd want that anyway.
December 11, 2018
On Tue, Dec 11, 2018 at 08:44:03AM +0000, aliak via Digitalmars-d wrote:
> On Monday, 10 December 2018 at 17:07:10 UTC, jmh530 wrote:
> > On Monday, 10 December 2018 at 15:47:53 UTC, aliak wrote:
> > > [...]
> > 
> > Does it make sense to deprecate Nullable as a whole, rather than just that piece? Why would I use Nullable when I can use your optional library?
> 
> I would be all for that. I guess the only reason would be to have
> pointer semantics for value types 🤷‍♂️And I'm not really sure why
> you'd want that anyway.

It's useful for representing a value that isn't there.  E.g., if I have a struct with some int fields parsed from some config file, say, I'd like to be able to distinguish between a field that's actually set, vs. one that isn't specified in the config file.


T

-- 
English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
December 11, 2018
On Tuesday, 11 December 2018 at 18:04:37 UTC, H. S. Teoh wrote:
> On Tue, Dec 11, 2018 at 08:44:03AM +0000, aliak via Digitalmars-d wrote:
>> On Monday, 10 December 2018 at 17:07:10 UTC, jmh530 wrote:
>> > On Monday, 10 December 2018 at 15:47:53 UTC, aliak wrote:
>> > > [...]
>> > 
>> > Does it make sense to deprecate Nullable as a whole, rather than just that piece? Why would I use Nullable when I can use your optional library?
>> 
>> I would be all for that. I guess the only reason would be to have
>> pointer semantics for value types 🤷‍♂️And I'm not really sure why
>> you'd want that anyway.
>
> It's useful for representing a value that isn't there.  E.g., if I have a struct with some int fields parsed from some config file, say, I'd like to be able to distinguish between a field that's actually set, vs. one that isn't specified in the config file.
>
>
> T

True! Sorry, I meant that as a response to "why would i use Nullable over the mentioned Optional library". In that case optional represents existence, and then the only thing nullable has over that is pointer semantics. But I think pointer semantics is a poor representation of the existence of a value. What's the difference between using Nullable!int and int* to see if it's set in terms of intent/semantics/safety? (I realize allocation would be a difference).

Cheers,
- Ali



December 11, 2018
On Tuesday, December 11, 2018 2:48:36 PM MST aliak via Digitalmars-d wrote:
> On Tuesday, 11 December 2018 at 18:04:37 UTC, H. S. Teoh wrote:
> > On Tue, Dec 11, 2018 at 08:44:03AM +0000, aliak via
> >
> > Digitalmars-d wrote:
> >> On Monday, 10 December 2018 at 17:07:10 UTC, jmh530 wrote:
> >> > On Monday, 10 December 2018 at 15:47:53 UTC, aliak wrote:
> >> > > [...]
> >> >
> >> > Does it make sense to deprecate Nullable as a whole, rather than just that piece? Why would I use Nullable when I can use your optional library?
> >>
> >> I would be all for that. I guess the only reason would be to
> >> have
> >> pointer semantics for value types 🤷‍♂️And I'm not really sure why
> >> you'd want that anyway.
> >
> > It's useful for representing a value that isn't there.  E.g., if I have a struct with some int fields parsed from some config file, say, I'd like to be able to distinguish between a field that's actually set, vs. one that isn't specified in the config file.
> >
> >
> > T
>
> True! Sorry, I meant that as a response to "why would i use Nullable over the mentioned Optional library". In that case optional represents existence, and then the only thing nullable has over that is pointer semantics. But I think pointer semantics is a poor representation of the existence of a value. What's the difference between using Nullable!int and int* to see if it's set in terms of intent/semantics/safety? (I realize allocation would be a difference).

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. 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.

And IMHO, the arguments about Nullable vs Optional vs Maybe etc. are mostly nonsense in that it's really just an argument about how the type is named. And while names matter, any of those names work just fine, and it's ultimately very subjective. It's like arguing about whether strip or trim is a better function name for a function that removes whitespace from the end of strings. Either name works just fine. The difference is pretty much just a difference in preference or expectation based on what the programmer has seen other languages or libraries do. It's entirely subjective.

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). So, based on that, it could be argued that Nullable is a worse name, but originally, since it didn't even allow types that were themselves nullable, that was a non-issue, and at this point, we don't change the names of things in Phobos just because we decide that another name is better, because Walter and Andrei don't think that that's worth the code breakage. To change or replace Nullable, we'd need a reason other than some folks wanting a different name in order to change it. The alias issue is arguably worth a deprecation given how code that uses a Nullable really should be written with the idea that it could be null rather than having an actual value, and having the alias makes it easier to introduce bugs related to that, but that doesn't require replacing Nullable or changing how it fundamentally works. It just means deprecating the alias. Nullable itself can continue to function the same way, and plenty of code using Nullable would not need to be changed due to deprecating the alias.

If someone prefers some other implementation of what Nullable is doing, they're free to use that instead, but most of the arguments around replacing Nullable seem to either revolve around the fact that some folks don't like the name or the fact that they think that a Nullable containing a type that can be null should use whether the value is null to determine whether the Nullable is null/empty instead of using a separate bool, and IMHO, doing so would just be a source of bugs. Also, at least some existing code relies on that functionality (e.g. it's been mentioned before that vibe.d relies on it).

- Jonathan M Davis




December 13, 2018
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. The fact that you can use D's Nullable to avoid allocating an int* is a happy proxy effect at best and only applies to a subset of types T can take on.

And now I've heard three reasons for the purpose of Nullable:

* It's an optional/maybe type
* It's to give value types pointer semantics
* And now, it's to avoid heap allocations for value types

AFAIK, Nullable was modeled after C#'s Nullable. Which only applies to value types - and that makes sense. But the way it's used in D is just a pothole of confusion and WTFs (see below).

> 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.

>
> And IMHO, the arguments about Nullable vs Optional vs Maybe etc. are mostly nonsense in that it's really just an argument about how the type is named. And while names matter, any of those names work just fine, and it's ultimately very subjective. It's like arguing about whether strip or trim is a better function name for a function that removes whitespace from the end of strings. Either name works just fine. The difference is pretty much just a difference in preference or expectation based on what the programmer has seen other languages or libraries do. It's entirely subjective.

It can be subjective, but there are also objectively better names and better APIs. And IMO we shouldn't settle for "fine" if we don't have to. Right now, I can accurately say this about Nullable:

Nullable is a type that can be null, but may not be null even if assigned null.

Is it subjective that that's good or bad? I personally think it's objectively bad.

>
> 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??

Cheers,
- Ali



December 13, 2018
On Tuesday, 11 December 2018 at 22:32:45 UTC, Jonathan M Davis wrote:
> 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).

Could you elaborate on some of those subtle bug? And are they worse than the following?

---
import std.typecons;
class C {
}
void main() {
    Nullable!C c;
    assert(c.isNull);
    c = null;
    assert(!c.isNull);
}
---

What about having Nullable!T* decay into a wrapped pointer. Why does it need to keep its own bool when that information can be captured in the pointer?

Or is there some difference between a Nullable!T* with a null value and one with no value? I thought no value and null to be the same thing. But if it is, why is it called Nullable?