I'm personally tired of staring at variables trying to figure out what they're supposed to be, then having to dive into source to see how its used. C/C++/C# solved that problem, why are we still dealing with it?
How does nobody(?) support this yet?
Python supports some parts: you can subclass int, and you get all of the int methods like addition and subtraction for free, but "distanceInKm + distanceInKm" gives you an int instead of a distanceInKm; and "distanceInKm + distanceInMiles" gives you an int instead of an error.
Rust also has partial support but from the other end: distanceInMiles and distanceInKm can be two distinct subclasses of int, and adding them together is a compile time error. But also adding distanceInMiles with distanceInMiles is a compiler error, because these are basically "completely new classes" rather than "subclasses of int", and so you have to implement add / subtract / stringify / etc for yourself for every type D: (I'm fairly new to Rust so if there is a shortcut there that I'm missing please do point it out)
newtype Pixel = Pixel Int
newtype Em = Em Int
pixelWidthToEm :: Pixel -> Em
pixelWidthToEm (Pixel px) = Em px
You can try to call `pixelWidthToEm` with anything other than pixels and it won't work.More dynamically, with an open type variable that only exists in the type system:
data User a =
User { name :: String, socialSecurityNumber :: String }
data LogSafe
data LogUnsafe
logUser :: User LogSafe -> IO ()
logUser = undefined
makeUserLogSafe :: User LogUnsafe -> User LogSafe
makeUserLogSafe = undefined
We can never log the user unless the user is deemed LogSafe and we make functions that produce log safe users that you have to call before hand, in order to make sure that sensitive data isn't printed to logs.These are things that have been around for a long time in almost every type system, but people's general lack of interest in using type systems to help them conspires to keep them in the dark.
Here's how you can create a number type distinct from other number types in TypeScript:
type DistanceInPixels = number & { readonly __newtype__: "DistanceInPixels" }
And a type alias that allows you to create them: export type Newtype<T, Tag extends string> = T & { readonly __newtype__: Tag }
type Pixels = Newtype<number, "Pixels">In any case, to answer the question of "How does nobody(?) support this yet?", have you heard of https://frinklang.org/ ? It's not a useful tool for most codebases I work on but it's an interesting idea.