Fp-ts: Suggestion: change the internals of Option type

Created on 23 Oct 2020  路  4Comments  路  Source: gcanti/fp-ts

馃殌 Feature request

Current Behavior

Currently Option has type

interface None {
  readonly _tag: 'None'
}

interface Some<A> {
  readonly _tag: 'Some'
  readonly value: A
}

type Option<A> = None | Some<A>

Desired Behavior

type None = null | undefined

type Option<A> = None | A

Rationale

  • Better and easier integration with any other code and TypeScript in general, any value that can be null or undefined already has type Option
  • Easier serialization, sending Option to backend won't look confusing and won't require additional efforts
  • Less memory consumed, no need to wrap a value inside an object
  • No need to transforom from/to undefined/null, both of these values are already None, it's possible to just use them without transforming

I can prepare the PR myself if it will be considered a good idea

Most helpful comment

You can't encode Option<Option<A>> or Option<A | null> with this.

All 4 comments

You can't encode Option<Option<A>> or Option<A | null> with this.

@xuanduc987 good point, but could you please elaborate? It should be actually possible:

type Option<T> = T | null | undefined
const never: Option<never> = undefined
const some = <A>(a: A): Option<A> => a

let opt1: Option<Option<number>> = some(some(1))
opt1 = some(never)
opt1 = never

let opt2: Option<number | null> = some(1)
opt2 = some(null)

@denistakeda
Is null a never, or a some(never), or some(some(never))? It is important for things typeclassesCompactableand functions likecompact` in order to work properly.

a) Your data type does not represent the _possibility_ of having data or not having it (two cases) as you may believe. It represents the reality of _always_ having data, and not two but three different cases to handle ( A | null | undefined). If anything this would lead to more boilerplate when dealing with Option, not less.

b) As others already pointed out, your data type definition makes several instances not implementable. Imagine a series of nullable computations I may want to know which one failed, your data type cannot represent it, because it cannot represent a nested Option in the first place. Moreover, why would I have to be limited by not being able to represent Some<null> or Some<Some<null>>, There's difference between receiving a null from an external api or an undefined, or a key that is defined, but it's value is undefined. Leaking language specifications into a data type is pretty dangerous and makes code, imho, more bug-prone, harder to read and reason about.

c) About the serialization/deserialization issue: the proposed implementation seems unsafe. If anything an Option forces me to handle whether I want an undefined or a null value. undefined is not a valid JSON value, null is.
Your proposed implementation still forces me to handle 3 cases, not just 2. If all you want out of the fold is to have A | undefined it's literally a line of code. Leaking undefined and nulls in application code, rather than at its borders (when communicating with a third party api, either software or some server) is generally dangerous and what type safety tries to avoid. The proposal seem to go into the opposite direction.

d) About the memory issue: could you show any realistic scenario where you had memory bloating by appending a _tag to a data structure? This kind of micro-optimizations are fine as long as they are corroborated by evidence of tangible benefits.

Jm2c but I think you're simply looking for a Nullable type in your code (for which your definition is enough) and you're not interested in all the instances the Option data type offers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

amaurymartiny picture amaurymartiny  路  4Comments

FruitieX picture FruitieX  路  3Comments

bobaaaaa picture bobaaaaa  路  4Comments

FredericLatour picture FredericLatour  路  3Comments

steida picture steida  路  4Comments