Lowtype: Elegant types in Ruby
17 points by pushcx
17 points by pushcx
This seems to be more of an assertion at runtime instead of type checking at compile/eval time. This means that it doesn't really help to avoid runtime errors. Sure, it will at least avoid data corruption, but in a type checker like mypy if the code pass I have some confidence it will work correctly (yes, there are corner cases it doesn't help, I know).
Sadly because the syntax does looks nice, much better than Sorbet and RBS.
the syntax does look very nice! you could probably build an external type checker to work with it; that's how python type checking works after all.
I appreciate the experiment, but what value people get from runtime checks? It's something I never got into.
Sorbet uses both runtime and static checks to type check Ruby. Misunderstanding the value of runtime checks is a common point, and I’ve written about it a little in the past:
When adding types to an untyped language, the biggest poison is the fact that the types might be wrong, because they give you a false sense of security (vs languages which were typed from day one). Runtime checking means you leverage your test coverage into type coverage, and fail fast in production if the annotation ended up being wrong.
Entirely new languages like Crystal are built on the idea that you could make a Ruby-like type-safe language, with a compiler and a type checker that don't die at runtime. Crystal is pretty cool in fact. :)
On the other hand, there's nothing like Typescript for Ruby (as far as I know).
IMHO, one reason for this state of things is that DHH (the Ruby on Rails project lead) does not like the idea: as long as Rails isn't "typed", the rest of the Ruby ecosystem has a very low incentive to get on that wagon.
Let's keep experimenting meanwhile, experiments are fun.
one reason for this state of things is that DHH (the Ruby on Rails project lead) does not like the idea
Matz has said himself multiple times he doesn't want type annotations in Ruby.
Let's keep experimenting meanwhile, experiments are fun.
Sure, projects like these have existed forever. I just don't get why get runtime checks when sorbet could do it statically?
On the other hand, there's nothing like Typescript for Ruby (as far as I know).
https://sorbet.org is a thing, though I've not studied it in detail.
I dont think that’s quite the same thing. Typescript retains some of the look of JavaScript but it’s compiled down to JS.
Sorbet is a type checker.
I think that's a fairly superficial distinction. TypeScript, ignoring a couple niche features that most modern code doesn't use, has identical runtime semantics to JavaScript; the only thing the compiler does is strip out the type annotations. Sorbet's type annotations are valid Ruby syntax anyway, so it doesn't need a build step to strip them out.
Both TypeScript and Sorbet can be used as standalone type checkers - although tsc can work as a compiler, in my experience it's more common nowadays to use it as a typechecker only, and use another tool (eg Babel) to strip out the type annotations, a trivial operation, to produce the production JavaScript.
Fair enough, and thanks for updating me about that. (Luckily, I haven't looked at the JS/TS ecosystem in months. :p)
Personally I get 80% of the value of types just by adding YARD @param and @return comments above each method, so I'll know the argument types and the return value type. Doesn't need any tooling and it's always available.
In the 1990s, one of my teachers told me that most bugs are the result of people misunderstanding the input and output of a function. That still tracks for me, but I do like having my editor know about types so it can highlight some cases of that more easily to help me catch it.
My two primary criticisms of YARD docs are: first, that they add lines to the file which (when taken to excess) can make it difficult to get the whole of the code into view and, second, that the types aren't necessarily reflective of the actual type being returned, especially if you're duck typing anything.
I had an experience recently where a @return was useful because it was a one-line function where they were parsing a value out of a hash and there was no clear indicator otherwise that the return value was supposed to be a float (it was obvious it was a number, but unclear if it was a float or an integer), but they also could have accomplished the same thing by slapping a .to_f on the end.
Basically, if it's ambiguous what the params/return types should be, that smells to me like the code itself should be updated to reflect it better.
On the one hand, I think types are neat and useful. Having something like this (even at runtime) saves you the trouble of needing to write a guard clause asserting that the received argument is what you expect it is. Also as a sibling comment states the syntax is much nicer than Sorbet or RBS.
On the other hand, part of Ruby's flexibility is that you don't really care about types so much as the interface of the objects you're passing around. You care if an object receives a message. This means you can do things like set up Null Objects that fulfill the contract of a class so you can obviate the need for nil checks.
When I first saw the typing libraries for Ruby, I got more excited about them than I do now. Now I feel like it sort of misses the point of Ruby.
that just means that Ruby wants structural types, right? like the type of an object is not Foo, it is the set of messages that it can receive (which is given the name Foo for convenience). my experience with typing in other dynamic languages is that TypeScript's structural typing works very well, even for dynamic JS. PHP's nominal typing does not work so well, and is frequently painful (object A and B have satisfy the structure of the type but have different names and turn entirely valid duck-typed PHP into invalid strongly-typed PHP)
Btw, for the libraries that use Ruby's built-in reflection capabilities for type safety there is a major limitation: they can't type the reflection itself. Given that Ruby is built on the magic grounds itself typing it using its own runtime becomes unfeasible.