logoalt Hacker News

karmakazelast Sunday at 2:28 PM6 repliesview on HN

I haven't read this in detail but I expect it to be the same kind of sealed type that many other languages have. It doesn't cover ad-hoc unions (on the fly from existing types) that are possible in F# (and not many non-FP languages with TypeScript being the most notable that does).


Replies

CharlieDigitaltoday at 1:03 PM

IME, this is a good thing.

The problem with ad-hoc unions is that without discipline, it invariably ends in a mess that is very, very hard to wrap your head around and often requires digging through several layers to understand the source types.

In TS codebases with heavy usage of utility types like `Pick`, `Omit`, or ad-hoc return types, it is often exceedingly difficult to know how to correctly work with a shape once you get closer to the boundary of the application (e.g. API or database interface since shapes must "materialize" at these layers). Where does this property come from? How do I get this value? I end up having to trace through several layers to understand how the shape I'm holding came to be because there's no discrete type to jump to.

This tends to lead to another behavior which is lack of documentation because there's no discrete type to attach documentation to; there's a "behavioral slop trigger" that happens with ad-hoc types, in my experience. The more it gets used, the more it gets abused, the harder it is to understand the intent of the data structures because much of the intent is now ad-hoc and lacking in forethought because (by its nature) it removes the requirement of forethought.

    "I am here.  I need this additional field or this additional type.  I'll just add it."
This creates a kind of "type spaghetti" that makes code reuse very difficult.

So even when I write TS and I have the option of using ad-hoc types and utility types, I almost always explicitly define the type. Same with types for props in React, Vue, etc; it is almost always better to just explicitly define the type, IME. You will thank yourself later; other devs will thank you.

show 1 reply
let_rectoday at 12:16 PM

> ad-hoc unions (on the fly from existing types) that are possible in F#

Are you sure? This is a feature of OCaml but not F# IIUIR

Edit: https://github.com/fsharp/fslang-suggestions/issues/538

owlstuffingtoday at 12:52 PM

> It doesn't cover ad-hoc unions

Yes and no. C# unions aren’t sealed types, that’s a separate feature. But they are strictly nominal - they must be formally declared:

    union Foo(Bar, Baz);
Which isn’t at all the same as saying:

    Bar | Baz
It is the same as the night and day difference between tuples and nominal records.
show 1 reply
orthoxeroxtoday at 12:22 PM

Third paragraph from the top:

> unions enable designs that traditional hierarchies can’t express, composing any combination of existing types into a single, compiler-verified contract.

show 1 reply
dathinabtoday at 1:09 PM

it's basically `union <name>([<type>],*)`, i.e.

=> named sum type implicitly tagged by it's variant types

but not "sealed", as in no artificial constraints like that the variant types need to be defined in the "same place" or "as variant type", they can be arbitrary nameable types

mpawelskitoday at 2:58 PM

I'm pretty sure at one point there was proposal that allowed declaring something like `int or string`. Not sure what happened with it though.