4 ms·
>encoding that a number is between 2 and 200 What’s the point of this level of autism when you still have to add run time checks?
by what 11mo ago
>encoding that a number is between 2 and 200
What’s the point of this level of autism when you still have to add run time checks?
- kennywinker 11mo agoFor a function setVelocity() that can accept 1..<200. You call it with numbers that you enter directly and types tell you something that would otherwise be a comment on the function, or you do runtime checks elsewhere, and the type becomes proof that you checked them before handing it into the function. Btw, using “autism” to mean “pedantry” leaves a bit of a bad taste in my mouth. Maybe you could reconsider using it that way in the future.
- samdoesnothing 11mo agoPushing everything to types like this creates a different burden where you're casting between types all over the place just to use the same underlying data. You could just clamp velocity to 200 in the callee and save all that hassle.
- kennywinker 11mo agoCasting? Not really - i think you’d only need a couple type checks. Imo this is mostly useful for situations where you want to handle input validation (and errors) in the UI code and this function lives far away from ui code. Your point about clamping makes sense, and it’s probably worth doing that anyway, but without it being encoded in the type you have to communicate how the function is intended to be used some other way.
- samdoesnothing 11mo agoHow would you convert a Number type to a ClampedNumber type without casting?
- kennywinker 11mo agoAh, yeah you’re right. I somehow thought typescript could do type narrowing based on checks - like say: If (i >= 1) { // i’s type now includes >= 1 } But that is not the case, so you’d need a single cast to make it work (from number to ClampedNumber<1,200>) or however exactly you’d want to express this. Tbf having looked more closely into how typescript handles number range types, I don’t think I would ever use them. Not very expressive or clear. I think I hallucinated something closer to what is in this proposal: https://github.com/microsoft/TypeScript/issues/43505 https://github.com/microsoft/TypeScript/issues/43505 I still think that the general idea of communicating what acceptable input is via the type system is a good one. But the specifics of doing that with numbers isn’t great in typescript yet.
- samdoesnothing 11mo agoHow would you implement it in other languages that support it better? Can you literally just do a range check and the compiler infers its range for types? If so thats actually pretty neat.
- skydhash 11mo agoWhat about documentation as in docstring, function signature label and the like. I quite like CommonLisp, EmacsLisp, Go for that.
- kennywinker 11mo agoYeah, that’s probably the best possible implementation outside of the type system. The issue with docstrings is that they aren’t checked. So you’ve communicated the api to the coder, and maybe even to the ide, but not to the compiler.
- locknitpicker 11mo ago> Pushing everything to types like this creates a different burden where you're casting between types all over the place just to use the same underlying data. TypeScript does not perform any kind of casting at all. What TypeScript supports is structural typing, which boils down to allowing developers to specify type hints in a way that allows the TypeScript compiler to determine which properties or invariants are met in specific code paths. Literal types address a very common and very mundane use case: assert what can and cannot be done with an object depending on what value one of it's fields have. Take for example authorization headers. When they are set, their prefix tells you which authorization scheme is being used by clients. With typescript you can express those strings as a prefix constrained string type, and use them to have the TypeScript compiler prevent you from accidentally pass bearer tokens to the function that handles basic authentication. Literal types shine when you are using them to specify discriminant fields in different types. Say for example you have a JSON object that has a `version` field. With literal types you can define different types discriminated by what string value features in it's `version` field, and based on that alone you can implement fully type-safe code paths.
- samdoesnothing 11mo agoIf you have some `ConstrainedNumber` type, you will need to cast between it and `number`, either with a type assertion or with a type guard. In either case, when you use bespoke types everywhere you kill code reuse.
- epolanski 11mo agoBeing guaranteed that _at runtime_ you won't end up with 1 or 201.