Hacker News new | ask | show | jobs
by imiric 1079 days ago
Conversely, and I don't mean to sound flippant, but are there any pros of (ab)using types in this way?

These projects are interesting in an amusing "oh look, another Turing complete type system" way, for the author to gain expertise, and as something to highlight in CVs and to chat about during interviews. But other than that, I would never actually choose to use any of this in a real-world project. Depending on the stability of this API (TPI?), and subjecting colleagues to esoteric libraries would be a nightmare to maintain and support.

1 comments

The pros of any type-level logic all boil down to automatically enforcing something that you want to be enforced. The key word being _automatically_.

This can be frustrating in the moment sometimes, but other times a type can do two really powerful things:

1. prevent someone you’ve never spoken to from doing something legitimately dangerous 2. provide browsable documentation about the constraint its enforcing and how other places in the code resolve the constraint.

It doesn’t always work out that way, sure, but that’s the ideal types are striving for.

> provide browsable documentation about the constraint its enforcing and how other places in the code resolve the constraint.

It doesn't provide "browsable documentation". It provides complex unreadable types that you have to painstakingly manually "compile" in your head to figure out what the hell is going on

That doesn’t seem like a fair characterization in all cases.
It's a fair characterization because it's a common enough issue to become a problem. It's a compounding of several issues, really, of which "types are documentation" is just one:

- types are not documentation

- tests are not documentation

- code is not documentation

What would you call the ability of a type to communicate information such as the range of values that can be passed into a function?
I'd call it exactly that.

Note that there are very few languages that have those kinds of types. Usually it's enums and union types that usually tell you nothing about where to get those ranges, why those ranges exactly, or what those ranges mean.

Literally right now I'm looking at a GraphQL schema that tells me that for a collection of lists of data it returns the following list types: Generic, GenericV2, Onboarding, OnboardingActive... That's it. Actual call returns only a few of those with no apparent difference in actual data.

It is typed though.

Generally (at least if we're talking typescript and vscode), the IDE serves as a REPL UI for the type system.

You don't have to compile in your head; you can declare a variable or assignment with some type property and see where an error is thrown.

For errors that can be automatically fixed by IDE, yes. It doesn't make this documentation ;)

I've seen quite a few cases where IDE's type expansion (whether on hover or in type errors) would result in a dozen lines of nested types. Worse than no documentation at all.

A dozen lines of nested types are like a dozen lines of source code, and I generally recommend treating them the same if they aren't legible: poke it with a REPL (in this case, try to declare a variable or new type that should work if your understanding of the types are correct) and see what the tools say.

(And, of course, as with other source code, illegibility implies more documentation needed. For type systems in particular, I think people tend to under-declare their types [i.e. they'll do "Record<KeyType, Array<{name: string, address: string}>" instead of "Record<KeyType, EmployeeRecords>"], which gives the compiler fewer hooks to shortcut talking about a complex type).

There is one thing consistently true about type systems that frustrates me: I write in procedural code all day, but basically all type systems are functional code. It is frustrating to have to spin my reasoning around to attack a problem in a different language structure when I've been doing straight-line statement-by-statement all day. I don't have a solution to that, but I observe the challenge.

> A dozen lines of nested types are like a dozen lines of source code, and I generally recommend treating them the same if they aren't legible: poke it with a REPL (in this case, try to declare a variable or new type that should work if your understanding of the types are correct) and see what the tools say.

None of these actions make types documentation. The necessity to do this makes them a hindrance at best.

> I think people tend to under-declare their types [i.e. they'll do "Record<KeyType, Array<{name: string, address: string}>" instead of "Record<KeyType, EmployeeRecords>"

Oh god, so true :)

But projects like these go far beyond just constraints. They're a library of utility functions for doing arithmetic, working with lists, and even sorting. All of this can be equally accomplished by a regular and well-established library that doesn't depend on exotic, and possibly undocumented, features of a type system, and without incurring build time penalties.
Well, "constraint" is a very abstract word. What you're describing are still constraints, they're just complex constraints.

The type vs. no type argument is basically: what's the cutoff line for constraints that are worth encoding as types or not?