3 ms·
> Null is a perfectly valid and very useful feature, if modeled in the type system. No it isn't, because union types leak through generics in surprising ways.
by Nullabillity 2y ago
> Null is a perfectly valid and very useful feature, if modeled in the type system.
No it isn't, because union types leak through generics in surprising ways. For example:
// value is null if not loaded yet
struct AsyncSnapshot<T> { value: T? }
// returns null if user is not found
fn getUser(id: Id<User>): User?
fn runInBackground<T>(f: () -> T): Stream<AsyncSnapshot<T>>
If you run `runInBackground({ getUser(id) })`, `AsyncSnapshot<T?>`'s `value` gets the type `T??` which is typically coalesced to `T?` and you can't tell whether it's `null` because there is no user, or because it's still loading.
Sum types like `Option<T>` do not coalesce, `Option<Option<T>>` is distinct from `Option<T>`. Better yet, you can declare your own clearer sum types, so you can have `MaybeLoaded<MaybeExists<User>>` rather than have to remember which layer is which.
- tadfisher 2y agoThat doesn't make it not useful, but I agree with your conclusion.