← Back to context

Comment by kccqzy

6 days ago

> What folks should actually be asking is “Does my language need generics?”.

You should also ask “Does my language need subtyping such as subclasses?” And if the answer to both is yes, you should probably forget about Hindley Milner, or at least pick something far away from it on the spectrum.

In this case do yourself a favor and use something like simple-sub

https://github.com/LPTK/simple-sub

https://www.reddit.com/r/ProgrammingLanguages/comments/hpi54...

https://dl.acm.org/doi/10.1145/3409006

  • I have implemented simple-pub a few years ago in a toy project. And no, the type inference user experience is still way worse than what’s acceptable for a mainstream language.

    • That's interesting. Can you share some specifics? Like, what makes it worse?

      Anyway I didn't mean that simple-sub makes subtyping inference great. It (and mlsub) seems to be just better than previous approaches

HM handles sub-typing just fine? Numerous approaches have been known since the 1980s - Michael Wand’s row polymorphism is one such approach.

https://en.wikipedia.org/wiki/Row_polymorphism

  • Structural subtyping yes, nominal subtyping is a bit pricklier.

    As a developer I personally prefer structural subtyping, but structural subtyping is harder for a compiler to optimize runtime performance for.

    Nominal sub-type hierarchies allows for members to be laid out linearly and member accesses becomes just an offset whereas a structural system always has the "diamond problem" to solve (it's hidden from users so not a "problem" but will still haunt compiler/runtime developers).

    Now the kicker though, in practice nominal subtype polymorphism has other issues for performance on _modern_ computers since they create variable sized objects and cannot be packed linearly like monomorphic structures.

    In the 90s when languages settled on nominal typing memory speeds weren't really an huge issue, but today we know that we should rather compose data to achieve data-polymorphic effects and singular types should be directed to packing.

    Thus, most performance benefits of a nominal type system over a structural don't help much in real-life code and maintenance wise we would probably have been better off using structural types (iirc Go went there and interfaces in Java/C# achieves mostly the same effect in practice).

  • I've been implementing row polymorphism in my fork of Elm in order to support proper sum and substraction operations on unions, and it's far from trivial.

    Example usecase: an Effect may fail with 2 types, but actually you have handled one/catched one so you want to remove it.

    Elm-like HM systems handle fine, as you say it, row polymorphism mostly over records.

    I'm not an expert in all of this, started studying this recently, so take my words with a grain of salt.

Eh, generics kinda do introduce a subtyping relation already. It's just that HM's Gen rule of e: σ implies e: ∀α.σ is restrictive enough that this subtyping relation can be checked (and inferred) by using just unification which is quite an amazing result.