top | item 46488305

(no title)

tekne | 1 month ago

My personal preference would be to have separate types `A` and `A?` and overload field projections to work on `A?` as you'd expect. Subtyping optional.

Putting on my theory hat, while we we can overload field projection for any monad (data structure representing a result + an effect : think result for exceptions, or a thunk for a promise), it's not the best idea.

But for what is at least morally a commutative (order doesn't matter: FAIL ; pure = pure ; FAIL = FAIL) and idempotent (FAIL ; FAIL = FAIL) monad, it works...

Which justifies fun things, like lazy projections on promises!

discuss

order

PaulHoule|1 month ago

... or maybe in the definition of type A you can specify what

   ((A) null).someValue
or

  ((A) null).doSomething()
does at the field or method level. I guess there is the issue of how you figure out what the type is which depends of course on the language. Could be a better fit for C++ than all-virtual Java but I don't want to give the C++ any ideas to make that language more complex!

tekne|1 month ago

You could, but the issue is that now when I'm defining a type I need to think about it's nullable behaviour.

Versus if I instead view nullability as a way of transforming types (aka a functor) that works by reflection; this gives me some parametricity: the behaviour of my function will be the "same" regardless of which generic I slot in (though fields don't play that well with generics... something something row polymorphism something something).

Ill formed thoughts really; what I'm handwaving at is I slightly agree with the anti-complexity crowd that an operator should usually do the same thing, and yet I think it harms terseness and hence often readability and understanding to have non-overloaded boilerplate everywhere (addf64, addu32, addi16...).

Parametricity is a nice compromise for non-primitive ops, imo.