Jump to page: 1 2
Thread overview
What is the rationale behind enabling Nullable!T to be used as a regular T?
Feb 14, 2020
Adnan
Feb 14, 2020
FeepingCreature
Feb 14, 2020
DanielG
Feb 14, 2020
Adnan
Feb 14, 2020
FeepingCreature
Feb 14, 2020
Adnan
Feb 14, 2020
Eugene Wissner
Feb 14, 2020
Paul Backus
Feb 14, 2020
aliak
Feb 14, 2020
Elronnd
February 14, 2020
Nullable!T, as I understand is somewhat similar to Rust's Option<T>. It's meant to be an alternative to sentinel value based error checking.

In regular Rust code if you do something like

let x: Option<i32> = None;
println!("{}", x + 4);

It should throw compile error, since the `x` in `x + 4` is not checked for null. OpAdd<rhs = i32> is not implemented for Option<i32> for that reason.

Of course, you can get the value using the unwrap() method, which would create runtime crash for null option. However when typing-out "unwrap()" you understand what you are signing up for.


Back to D.

const Nullable!int a;
assert(a.isNull);
writeln(a + 4); // compiles with 0 warnings

Why is opBinary implemented for Nullable!T? Doesn't it defeat its purpose?


February 14, 2020
On Friday, 14 February 2020 at 08:54:41 UTC, Adnan wrote:
> What is the rationale behind enabling Nullable!T to be used as a regular T?

The rationale is we have a few more months to wait before the deprecation period for that functionality runs out and we can remove it. :)

> Back to D.
>
> const Nullable!int a;
> assert(a.isNull);
> writeln(a + 4); // compiles with 0 warnings
>
> Why is opBinary implemented for Nullable!T? Doesn't it defeat its purpose?

If you switch to 2.090.1, you will get warnings there. If you run with -de, the warnings will be errors.

---

The original reason was I believe that Nullable was never really intended to be Optional, it was intended to give types a "null" state like objects and pointers. Well, objects and pointers crash when you access them if they're null, so...

(No, it's not a very good reason.)
February 14, 2020
There's also the 'optional' package if you're looking for something more functional-program-ey:

https://code.dlang.org/packages/optional


February 14, 2020
On Friday, 14 February 2020 at 10:35:52 UTC, DanielG wrote:
> There's also the 'optional' package if you're looking for something more functional-program-ey:
>
> https://code.dlang.org/packages/optional

Not sure if this is any better

/+dub.sdl:
dependency "optional" version="~>1.0.0"
+/
import optional;

void main(const string[] args) {
    static import std;
    const auto n = no!int();
    std.writeln(n + 4); // []
}
February 14, 2020
On Friday, 14 February 2020 at 12:40:54 UTC, Adnan wrote:
> On Friday, 14 February 2020 at 10:35:52 UTC, DanielG wrote:
>> There's also the 'optional' package if you're looking for something more functional-program-ey:
>>
>> https://code.dlang.org/packages/optional
>
> Not sure if this is any better
>
> /+dub.sdl:
> dependency "optional" version="~>1.0.0"
> +/
> import optional;
>
> void main(const string[] args) {
>     static import std;
>     const auto n = no!int();
>     std.writeln(n + 4); // []
> }

It's by design. optional presents a range interface of length 0 or 1.

See the docs for more info: https://github.com/aliak00/optional/#summary
February 14, 2020
On Friday, 14 February 2020 at 08:54:41 UTC, Adnan wrote:
> Nullable!T, as I understand is somewhat similar to Rust's Option<T>. It's meant to be an alternative to sentinel value based error checking.
>
> In regular Rust code if you do something like
>
> let x: Option<i32> = None;
> println!("{}", x + 4);
>
> It should throw compile error, since the `x` in `x + 4` is not checked for null. OpAdd<rhs = i32> is not implemented for Option<i32> for that reason.

The two ends of the design spectrum (as I see it) are:
1. `Optional(T) x` as a range of [0,1] elements of type `T`. For all possible operations `op` on type `T` there exists an operation `Option(T).op` and the effect of executing is equivalent to `x.map!fun`. This is what aliak's optional package provides.

2. `Optional(T) x` behaves like a null-able pointer. The compiler statically prevents dereferencing if it can't prove that x is non-null. Such as scheme (although limited to just pointers for now) is work in progress:
https://github.com/dlang/dmd/blob/master/changelog/ob.md
February 14, 2020
On Friday, 14 February 2020 at 14:43:22 UTC, Petar Kirov [ZombineDev] wrote:
>
> The two ends of the design spectrum (as I see it) are:
> 1. `Optional(T) x` as a range of [0,1] elements of type `T`. For all possible operations `op` on type `T` there exists an operation `Option(T).op` and the effect of executing is equivalent to `x.map!fun`.

Edit: `x.map!op`.


February 14, 2020
On Friday, 14 February 2020 at 12:40:54 UTC, Adnan wrote:
> On Friday, 14 February 2020 at 10:35:52 UTC, DanielG wrote:
>> There's also the 'optional' package if you're looking for something more functional-program-ey:
>>
>> https://code.dlang.org/packages/optional
>
> Not sure if this is any better
>
> /+dub.sdl:
> dependency "optional" version="~>1.0.0"
> +/
> import optional;
>
> void main(const string[] args) {
>     static import std;
>     const auto n = no!int();
>     std.writeln(n + 4); // []
> }

With std.typecons post deprecation:

import std.typecons;

void main() {
  static import std;
  const auto n = Nullable!int();
  std.writeln(n.apply!(i => i + 4)); // Nullable!int()
}

February 14, 2020
On Friday, 14 February 2020 at 08:54:41 UTC, Adnan wrote:
> Nullable!T, as I understand is somewhat similar to Rust's Option<T>. It's meant to be an alternative to sentinel value based error checking.

Not exactly, as others have mentioned.  But there is https://github.com/moon-chilled/tenbots-opensource/blob/master/maybe.d (which originally comes from https://github.com/dkhasel/maybe-d, but I cleaned it up a bit).  At one point, I wrote a wrapper which would let you write a function with a return type of Maybe!T, but which actually returned objects of type T.  But that was a giant hack and not at all worth it.
February 14, 2020
On Friday, 14 February 2020 at 14:43:22 UTC, Petar Kirov [ZombineDev] wrote:
> On Friday, 14 February 2020 at 08:54:41 UTC, Adnan wrote:
> The two ends of the design spectrum (as I see it) are:
> 1. `Optional(T) x` as a range of [0,1] elements of type `T`. For all possible operations `op` on type `T` there exists an operation `Option(T).op` and the effect of executing is equivalent to `x.map!fun`. This is what aliak's optional package provides.

Very interesting. I always thought that Option<T> is a type-guard for enforced null checks (I could be wrong here). But seems to me that this design circles back to square 1: having the callee remember to check if the length of the range is 0 or 1. Which is essentially similar to check sentinel values (i.e. check if the binarysearch returns -1 as index). What languages do this?

What does Aliak's package provide that's fundamentally different to just returning a T[]? Empty T[] would mean `None` and a T[] with 1 item means `Some(T)`?

> 2. `Optional(T) x` behaves like a null-able pointer. The compiler statically prevents dereferencing if it can't prove that x is non-null. Such as scheme
Nim's optional works this way too:

import options

let v = none(int)
echo v + 4 # error

Scala:

val a: Option[Int] = None
println(a + 4) // compile error

Even C++:

#include <iostream>
#include <optional>

auto main() -> int {
   std::optional<int> a;
   std::cout << a + 4 << std::endl; // compile error
}

>(although limited to just
> pointers for now) is work in progress:
> https://github.com/dlang/dmd/blob/master/changelog/ob.md

Nice, any chance it's going to work with non-ptrs too?

« First   ‹ Prev
1 2