Jump to page: 1 2 3
Thread overview
Proposing std.typecons : Optional (with PR)
Jun 11, 2019
FeepingCreature
Jun 11, 2019
aliak
Jun 11, 2019
FeepingCreature
Jun 11, 2019
aliak
Jun 11, 2019
FeepingCreature
Jun 11, 2019
aliak
Jun 11, 2019
FeepingCreature
Re: Proposing std.typecons : Optional (with PR) + rant
Jun 11, 2019
Nick Treleaven
Jun 11, 2019
Aliak
Jun 11, 2019
Johannes Loher
Jun 12, 2019
Jacob Carlborg
Jun 12, 2019
FeepingCreature
Jun 12, 2019
aliak
Jun 12, 2019
aliak
Jun 12, 2019
FeepingCreature
Jun 13, 2019
Jacob Carlborg
Jun 11, 2019
Johannes Loher
Jun 11, 2019
Marco de Wild
Jun 11, 2019
FeepingCreature
Jun 11, 2019
Johannes Loher
June 11, 2019
Since my rfc regarding deprecating `alias get this` in Nullable (see https://github.com/dlang/phobos/pull/7060 ) encountered no meaningful criticism (as I'm tactfully choosing to interpret the total absence of reaction), but somebody mentioned that a new type may have more success, since it doesn't have to justify itself in the same way as a change to existing behavior, I present `Optional`: https://github.com/dlang/phobos/pull/7065 .

To reiterate the difference:

`Nullable` is the standard type for "adding an undefined value state to an existing type". It's being abused as an `Optional` type. Why "abused"? Well:

1. `get` is **undefined** if Nullable is null

2. `get` is called implicitly.

This is not good behavior for an `Optional` type! Since my attempt to turn `Nullable` into an `Optional` type encountered zero enthusiasm and mild resistance, I've started a second parallel attempt to introduce an `Optional` type from scratch.

(Translation: I've copypasted `Nullable` and changed a few names.)

Opinion? Anyone? Anyone at all? I'm so alone...
June 11, 2019
On Tuesday, 11 June 2019 at 07:46:38 UTC, FeepingCreature wrote:
> Since my rfc regarding deprecating `alias get this` in Nullable (see https://github.com/dlang/phobos/pull/7060 ) encountered no meaningful criticism (as I'm tactfully choosing to interpret the total absence of reaction), but somebody mentioned that a new type may have more success, since it doesn't have to justify itself in the same way as a change to existing behavior, I present `Optional`: https://github.com/dlang/phobos/pull/7065 .
>
> [...]

If we're going to put an optional type there, I would consider not copy pasting nullable as it has some other issues as well, and maybe nail the interface down properly? E.g. having an optional that's a range would be rather awesome. Have you looked at: https://code.dlang.org/packages/optional. It has a lot of other added features as well but those can be removed if they're too much.
June 11, 2019
On Tuesday, 11 June 2019 at 09:58:48 UTC, aliak wrote:
> If we're going to put an optional type there, I would consider not copy pasting nullable as it has some other issues as well, and maybe nail the interface down properly? E.g. having an optional that's a range would be rather awesome. Have you looked at: https://code.dlang.org/packages/optional. It has a lot of other added features as well but those can be removed if they're too much.

I've looked at that and I specifically disagree with the decision to make it a range; that's why I didn't just internally switch to dub optional. Ranges are not monads. We may wish we had a concept of monads but we don't; ranges are not a general replacement for any conceivable container. `Optional.front` is just *weird* and unintuitive at first glance. It's not a bad decision in isolation, but it doesn't fit what I consider "the D style" of type design.

Sorry if that explanation is too fuzzy.
June 11, 2019
On Tuesday, 11 June 2019 at 07:46:38 UTC, FeepingCreature wrote:
> Since my rfc regarding deprecating `alias get this` in Nullable (see https://github.com/dlang/phobos/pull/7060 ) encountered no meaningful criticism (as I'm tactfully choosing to interpret the total absence of reaction), but somebody mentioned that a new type may have more success, since it doesn't have to justify itself in the same way as a change to existing behavior, I present `Optional`: https://github.com/dlang/phobos/pull/7065 .
>
> To reiterate the difference:
>
> `Nullable` is the standard type for "adding an undefined value state to an existing type". It's being abused as an `Optional` type. Why "abused"? Well:
>
> 1. `get` is **undefined** if Nullable is null
>
> 2. `get` is called implicitly.
>
> This is not good behavior for an `Optional` type! Since my attempt to turn `Nullable` into an `Optional` type encountered zero enthusiasm and mild resistance, I've started a second parallel attempt to introduce an `Optional` type from scratch.
>
> (Translation: I've copypasted `Nullable` and changed a few names.)
>
> Opinion? Anyone? Anyone at all? I'm so alone...

I agree that Nullable has behaviour that is unwanted. However, does this really warrant a new type in the standard library that contains the same functionality but with different implementation details? From the perspective of someone who is not too familiar with the standard library, which one do they need to choose? Why would they pick Optional over Nullable? Why would they pick Nullable over Optional? If Optional coexists with Nullable, IMO it needs to have a distinct use case to prevent confusion.

I would prefer to fix Nullable and have one consistent way of dealing with this problem in the standard library, rather than a (so it seems) "battle" between Nullable and Optional fighting for attention and usage. I don't know if any Phobos' functions use Nullable, but those would need to be updated to work with Optional as well (for said consistency).

I didn't comment earlier, but I am in favour of your earlier pull request.
June 11, 2019
On Tuesday, 11 June 2019 at 11:02:34 UTC, Marco de Wild wrote:
> I agree that Nullable has behaviour that is unwanted. However, does this really warrant a new type in the standard library that contains the same functionality but with different implementation details? From the perspective of someone who is not too familiar with the standard library, which one do they need to choose? Why would they pick Optional over Nullable? Why would they pick Nullable over Optional? If Optional coexists with Nullable, IMO it needs to have a distinct use case to prevent confusion.
>
> I would prefer to fix Nullable and have one consistent way of dealing with this problem in the standard library, rather than a (so it seems) "battle" between Nullable and Optional fighting for attention and usage. I don't know if any Phobos' functions use Nullable, but those would need to be updated to work with Optional as well (for said consistency).
>
> I didn't comment earlier, but I am in favour of your earlier pull request.

My impression is that the distinction turns on whether the null case can be expected to occur in "normal use" of the type. As `Nullable` says, accessing `get` while the `Nullable` `isNull` is *undefined*; that is, at the level of accessing missing array keys. (Except you can access them implicitly.) From this I infer that `Nullable` is mostly supposed to be non-null, maybe to enable delayed initialization or the like, which would justify the `alias get this` and match the unittests.

This is a *very* different thing from an `Optional` type! An `Optional` type is expected to be unset in normal operation. (That's why my implementation throws an Exception on access, not an Error.) That is, the user is expected to regularly encounter `Optional`s whose value is absent, and handle this state in his ordinary control flow. Hence no implicit alias, and no AssertError on access.

I too, would prefer to get `Nullable` into a state where it can serve as an Optional type. However, given the amount of forum interest in this has been an approximate **zero**, I've chosen to take any and every avenue that may at some point lead to a sane Optional type in the standard library. I am **sick** of spending hours debugging `alias get this` issues, or being told that a coworker spent hours debugging an `alias get this` issue. Whatever gets me rid of them, I will do. I don't care which of these PRs gets attention. The `Optional` PR does not obsolete the `deprecate alias get this` PR. If either of them gets traction, I will be glad of it.
June 11, 2019
On Tuesday, 11 June 2019 at 10:01:18 UTC, FeepingCreature wrote:
> On Tuesday, 11 June 2019 at 09:58:48 UTC, aliak wrote:
>> If we're going to put an optional type there, I would consider not copy pasting nullable as it has some other issues as well, and maybe nail the interface down properly? E.g. having an optional that's a range would be rather awesome. Have you looked at: https://code.dlang.org/packages/optional. It has a lot of other added features as well but those can be removed if they're too much.
>
> I've looked at that and I specifically disagree with the decision to make it a range; that's why I didn't just internally switch to dub optional. Ranges are not monads. We may wish we had a concept of monads but we don't; ranges are not a general replacement for any conceivable container. `Optional.front` is just *weird* and unintuitive at first glance. It's not a bad decision in isolation, but it doesn't fit what I consider "the D style" of type design.
>
> Sorry if that explanation is too fuzzy.

The explanation is a start :)

Ranges are not monads in the strictly mathematical sense you mean or? Why do you say this?

You can add a .get or .value to a range as well to not have the weirdness. Though ranges and their .front are a central concept in D so it should be understood *if* option is defined as a range.

Plus, whether or not you agree ranges are/can be monads or not is a tangential issue to seeing an optional as a monad or a collection (it's not mutually exclusive). In scala for e.g. it's a collection (also a monad), rust implements FromIterator and IntoIterator, haskell adheres to foldable, applicative, traversable and i guess others...

I'm not saying it has to be a range either, but you lose out on functional composition if it's not. Or you re-implement all the stuff from std.range/algorithm you want as part of option's interface to get them.
June 11, 2019
On Tuesday, 11 June 2019 at 11:56:01 UTC, aliak wrote:
> On Tuesday, 11 June 2019 at 10:01:18 UTC, FeepingCreature wrote:
>> I've looked at that and I specifically disagree with the decision to make it a range; that's why I didn't just internally switch to dub optional. Ranges are not monads. We may wish we had a concept of monads but we don't; ranges are not a general replacement for any conceivable container. `Optional.front` is just *weird* and unintuitive at first glance. It's not a bad decision in isolation, but it doesn't fit what I consider "the D style" of type design.
>>
>> Sorry if that explanation is too fuzzy.
>
> The explanation is a start :)
>
> Ranges are not monads in the strictly mathematical sense you mean or? Why do you say this?
>
> You can add a .get or .value to a range as well to not have the weirdness. Though ranges and their .front are a central concept in D so it should be understood *if* option is defined as a range.
>
> Plus, whether or not you agree ranges are/can be monads or not is a tangential issue to seeing an optional as a monad or a collection (it's not mutually exclusive). In scala for e.g. it's a collection (also a monad), rust implements FromIterator and IntoIterator, haskell adheres to foldable, applicative, traversable and i guess others...
>
> I'm not saying it has to be a range either, but you lose out on functional composition if it's not. Or you re-implement all the stuff from std.range/algorithm you want as part of option's interface to get them.

Right, my point is that in functional languages things like monads or generic interfaces in general are used to compose reusable containers into larger processing chains. However, I see `Optional` less as a container and more as a metaphor. As a metaphor, it's not "a range of elements with a length of either 0 or 1", it's "a type that may be either of those type's values plus 'unset'". That's not something that easily lends itself to the set of verbs that are used to manipulate ranges.

D is not a functional language, it's a multiparadigm language. It shouldn't be afraid to have a type that deviates from the functional paradigm if the functional paradigm is a bad metaphoric fit for the semantic message that the type expresses.
June 11, 2019
On Tuesday, 11 June 2019 at 12:01:34 UTC, FeepingCreature wrote:
> On Tuesday, 11 June 2019 at 11:56:01 UTC, aliak wrote:
>> On Tuesday, 11 June 2019 at 10:01:18 UTC, FeepingCreature wrote:
>>> I've looked at that and I specifically disagree with the decision to make it a range; that's why I didn't just internally switch to dub optional. Ranges are not monads. We may wish we had a concept of monads but we don't; ranges are not a general replacement for any conceivable container. `Optional.front` is just *weird* and unintuitive at first glance. It's not a bad decision in isolation, but it doesn't fit what I consider "the D style" of type design.
>>>
>>> Sorry if that explanation is too fuzzy.
>>
>> The explanation is a start :)
>>
>> Ranges are not monads in the strictly mathematical sense you mean or? Why do you say this?
>>
>> You can add a .get or .value to a range as well to not have the weirdness. Though ranges and their .front are a central concept in D so it should be understood *if* option is defined as a range.
>>
>> Plus, whether or not you agree ranges are/can be monads or not is a tangential issue to seeing an optional as a monad or a collection (it's not mutually exclusive). In scala for e.g. it's a collection (also a monad), rust implements FromIterator and IntoIterator, haskell adheres to foldable, applicative, traversable and i guess others...
>>
>> I'm not saying it has to be a range either, but you lose out on functional composition if it's not. Or you re-implement all the stuff from std.range/algorithm you want as part of option's interface to get them.
>
> Right, my point is that in functional languages things like monads or generic interfaces in general are used to compose reusable containers into larger processing chains. However, I see `Optional` less as a container and more as a metaphor. As a metaphor, it's not "a range of elements with a length of either 0 or 1", it's "a type that may be either of those type's values plus 'unset'". That's not something that easily lends itself to the set of verbs that are used to manipulate ranges.

It does actually. I use it like a range all the time:

arrayOfStuff
  .map!maybeParseThing
  .each!processThing;

Your argument against it being a range sounds a bit too philosophical. I think we should  consider the actual technical advantages/disadvantages of having it as a range or not. And if not, at least getting functions like map/flatmap/each/whatever as usable with optional.

I basically think a bit of thought should be put in to putting an optional type in the standard library instead of copying nullable (as mentioned, the range thing is not the only problem - another big one is treating null as a valid value for classes).

June 11, 2019
On Tuesday, 11 June 2019 at 12:30:10 UTC, aliak wrote:
> Your argument against it being a range sounds a bit too philosophical. I think we should  consider the actual technical advantages/disadvantages of having it as a range or not. And if not, at least getting functions like map/flatmap/each/whatever as usable with optional.
>

We have "map for Optional/Nullable", that's `apply`.

> I basically think a bit of thought should be put in to putting an optional type in the standard library instead of copying nullable (as mentioned, the range thing is not the only problem - another big one is treating null as a valid value for classes).

That's a fundamental problem with D though. Null *is* a valid value for classes. Making a class type optional just means that you're adding *another* type that also means "absent" at a different level of abstraction.

Was it the right decision to allow null in class types? Who knows. (No.) But I don't think that's a decision that should be patched in library types.
June 11, 2019
On Tuesday, 11 June 2019 at 13:55:52 UTC, FeepingCreature wrote:
> On Tuesday, 11 June 2019 at 12:30:10 UTC, aliak wrote:
>> (as mentioned, the range thing is not the only problem - another big one is treating null as a valid value for classes).
>
> That's a fundamental problem with D though. Null *is* a valid value for classes.

It is accepted but it is not valid. There is no object there, you can't dereference it (unless null is a valid memory address, which it is in some cases). Null is a gaping hole in any static type system.

Rant:
IMO the worst thing Walter ever said was "Non-nullable pointers are just plugging one hole in a cheese grater":
https://twitter.com/walterbright/status/338821357762654208

Optional types with language enforcement can allow a static guarantee that any data is constructed with particular values, returning an optional that is none when the initializer was outside those values.

I'd actually rather have language-assisted optional types than features like function overloading (a convenience feature, sometimes abused), because it means *the type system can model runtime checks as a static type guarantee*. They are a game changer.

> Making a class type optional just means that you're adding *another* type that also means "absent" at a different level of abstraction.

Re-use null to mean absent.

> Was it the right decision to allow null in class types? Who knows. (No.) But I don't think that's a decision that should be patched in library types.

Then I vote against including your Optional.
« First   ‹ Prev
1 2 3