Proposal: Automatically collapse nested @unboxed variants (Null.t<Null.t<'a>> => Null.t<'a>)

I’ve been looking at the rescript-core PRs and noticed a comment about the new representation of untagged variants:

I suddenly got thought that in case we create a type Nullable.t<Nullable.t<'a>> like Present(Null) it’ll match Null instead of Present(Null) which might cause an unwanted behaviour.

Then I remembered an interesting post from @cristianoc where he shares his thoughts about collapsing the option type and describes the pros and cons of doing it.

I want to resurrect the idea and share it with you because I think it might be interesting, safe, and good DX-wise to have the behavior for untagged variants where variant<variant<'a>> automatically becomes variant<'a>.

Although I’m not sure whether it’s technically possible. Also, if we have Nullable.t<Null.t<'a>> the problem where Present(Null) is matched as Null will stay.

1 Like

I thought the limitation with untagged variants was that the possible values should be easily distinguished at runtime. So maybe with the definition of Nullable.t proposed by @tsnobip, either Nullable.t<Nullable.t<'a>> is impossible, or the new definition itself.

That said, I think in a lot of cases noone would care about the difference between Present(Null) and Null, but then again, there is, e.g., a difference between Some(None) and None in filterMap.

Are you saying the typechecker will tell you some nested thing is flat, eg to the typechecker, any foo<foo<'a>> becomes foo<'a>?

Yes, something like this. Probably, should have the same logic for formatter.

Won’t this get you in to the same trouble that promises do? (eg this or this) Or is it because it’s just for the unboxed variants that it will be fine?

1 Like