(no title)
0xb0565e487 | 2 years ago
I'm imagining a language where I could define a custom data type with a regular function. For instance, I could have a method that the compiler would use to verify the validity of what I input, as shown below:
function PercentType(value: number) { if (value > 100 || value < 0) throw new Error();
return true;
}Is the lack of such a feature in TypeScript (or any language) a deliberate design decision to avoid unnecessary complexity, or due to technical constraints such as performance considerations?
lolinder|2 years ago
Ranges like percent are much trickier—TypeScript would need to compute the return type of `Percent + Percent` (0 <= T <= 200), `Percent / Percent` (indeterminate because of division by zero or near-zero values), and so on for all the main operators. In the best case scenario this computation is very expensive and complicates the compiler, but in the worst case there's no clear correct answer for all use cases (should we just return `number` for percent division or should we return `[0, Infinity]`?).
In most mainstream programming languages the solution to this problem is to define a class that enforces the invariants that you care about—Percent would be a class that defines only the operators you need (do you really need to divide Percent by Percent?) and that throws an exception if it's constructed with an invalid value.
wk_end|2 years ago
Another interesting point of reference are "refinement types", which allow you to specify things like ranges to "refine" a type; the various constraints are then run through a kind of automated reasoning system called an SMT solver to ensure they're all compatible with each other.
0xb0565e487|2 years ago
n2d4|2 years ago
It makes a lot of things impossible. For example, if you defined two different types of ranges, OneToFifty and OneToHundred similarly to your PercentType above, the following code would be problematic:
Any human programmer would say the third line makes sense because every OneToFifty number is also OneToHundred. But for a compiler, that's impossible to determine because JavaScript code is Turing-complete, and so it can't generally say that one is certainly a subset of the other.In other words, any two custom-defined types like that would be unassignable from and to each other, making the language much less usable. Now add generics, co-/contravariance, type deduction, etc., and suddenly it becomes clear how much work adding a new type to the type system is; much more than just a boolean function.
That said, TypeScript has a lot of primitives, for example, template string types for five-digit zip codes:
(Actually, some of these are Turing-complete too, which means type-checking will sometimes fail, but those cases are rare enough for the TS team to deem the tradeoff worth.)jerf|2 years ago
There's sort of a meme where you should never ask why someone doesn't "just" do something, and of all the people you shouldn't ask that of, programming language designers are way, way up there. Every feature interacts not just with itself, not just with every other feature in the language, but also in every other possible combination of those features at arbitrary levels of complexity, and you can be assured that someone, somewhere out there is using that exact combination, either deliberately for some purpose, or without even realizing it.
0xb0565e487|2 years ago
bern4444|2 years ago
Similarly for zip codes you could create a union of all possible zip codes like this:
Often with the idea you have in mind the solution is to implement an object where the constructor does a run time check of the requirements and if the checks pass instantiate the instance and otherwise throw a run time error.In functional programming this is often handled with the Option which can be thought of as an array with exactly 0 or 1 elements always. 0 elements when a constraint is not met and 1 element when all constraints are met.
This [0] is a library I wrote for JS/TS that provides an implementation of Options. Many others exist and other languages like Rust and Scala support the Option data structure natively.
[0] https://github.com/sbernheim4/excoptional
0xb0565e487|2 years ago
hn_throwaway_99|2 years ago
This is somewhat supported with template literal types, https://www.typescriptlang.org/docs/handbook/2/template-lite.... However, there are good technical/performance reasons they don't support, for example, plain regexes - there is a HUGE discussion on this topic here, https://github.com/microsoft/TypeScript/issues/6579.
golergka|2 years ago