Skip to content

Instantly share code, notes, and snippets.

@atacratic
Last active November 26, 2018 22:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atacratic/3a24bafe05e638f364b8d58141b07841 to your computer and use it in GitHub Desktop.
Save atacratic/3a24bafe05e638f364b8d58141b07841 to your computer and use it in GitHub Desktop.

(Following up the note here.)

Should we even have structural types? What if we just had nominal types only?

In favour of this: less to learn. Having two kinds of type, especially where the difference is so subtle to explain, is a significant spend on our complexity budget.

This idea initially felt surprising, since the structural approach to types is the analogue of how Unison treats terms. But maybe the analogy with terms is misleading. When you're defining a term, it is nothing other than its contents. When you're defining a type, part of what you're doing is constructing an equivalence class of terms, and it's not clear that the id-by-content idea should carry over to that.

What would we lose by dropping structural types?

Consider structural List a = Nil | Cons a (List a). Two people can define this type in different codebases at different times, and their code, if and when it interacts later, will be able to exchange lists with no problems.

But how much is that actually worth?

  • People won't define a type like List, but rather will expect to use a version from some kind of prelude.
    • And when you get beyond prelude-level stuff, is it really so common for types to have only one canonical meaning determined by their structure?
    • Maybe that canonicity is something that arises for container types (something to do with parametricity maybe) and not much otherwise.
    • For example, I bet that for any product type that contains members of known type (not just type variables), we can also construct an alternative interpretation of those members where we'd want a different overall type that is nonetheless structurally similar. (I had Person and Wine in my example here.)
  • If we only had nominal types, and code from two authors with two different List types comes into contact, then one of them can refactor all their code to use the List type defined by the other. We can make that a trivial operation.
  • If a (structural) dup already exists in the codebase, we could warn at the time of adding the definition.

So, seems like it's not actually worth that much? Or what am I missing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment