Long before Sorbet existed I explored type signatures for Ruby -- I even used `#sig` (I suppose it is the obvious choice). From that experience, I am perplexed by Sorbet's verbose syntax. Why the use of `#params`? Is it just to be able to add return types as a method call?
After my experiments I came to the conclusion that type information would probably be better if specified in structured comments, something like TomDoc. That way type information would be had just by writing the documentation one should be writing anyway. (Two birds, one stone.) It would also make the type signatures very readable.
Strongly agreed. I think there is a kind of x/y situation¹ going on with regard to Ruby type annotations. Are we trying to make it easier for developers to scan the code and understand what's going on? If so, then type signatures are more like a form of enforced documentation. Or are we interested in the ability to perform static analysis and catch bugs in an automated fashion? Then type signatures are something else.
My beef with Sorbet is that it seems like these two goals have been conflated a bit. While it's true that they aren't entirely orthogonal to each other, you definitely optimize for different things depending on which goal is more important.
If I'm primarily interested in developer understanding, then it's really important to use a DSL for annotations that's easy to visually scan and parse. I don't think Sorbet is great in that department. Even among Sorbet advocates, I often hear complaints about the syntax. That's because there's a direct correlation between the expressiveness of a language (Ruby being very expressive), and the expressiveness of the DSL you need to describe that language.
Sorbet went with an approach that tries to capture as much of Ruby's expressiveness as possible. But the reality of day-to-day Ruby programs is often that you could capture 90% of the use cases with 10% of the DSL footprint. If your primary heuristic is developer ease-of-understanding, then leaving that remaining 10% language coverage on the floor could be your best option.
Something like Typescript has its cake, and eats it too, by virtue of becoming its own language -- it's able to be very expressive while still remaining relatively easy to scan and parse. On the other hand, Sorbet is fighting with one hand tied behind its back in having to stick to standard Ruby syntax.
A few years ago at Shopify, I worked on an internal comment-based type checker for Ruby that would instrument our methods at runtime, and compare their inputs/outputs to what was declared above in YARDOC. It was definitely skewed more towards developer understanding than program-correctness. You couldn't really use it for static analysis, but it was pretty good at providing guidance unobtrusively. It was just comments, after all -- you could color them however you liked in your editor.
Right before we started adopting Sorbet in our monolith, we had high-level discussions about which type checker we wanted to use, and we ultimately went with Sorbet. I think that was probably the right call (more cumulative momentum). But I do still wish that Sorbet optimized a bit more for ease-of-understanding by restricting itself to a simpler DSL (at the expense of some descriptiveness).
It's possible to write a YARDOC-to-rbi converter so that you can still rely on comments instead of having to pepper your code with Sorbet annotations proper, but I haven't seen much use of that in the wild. We used such a converter at Shopify for migrating off of YARDOCs in places, though.
So what was/is the strategy at Shopify for typing - was the policy everything is going to eventually be typed? If so, I don't understand all the JIT/CRuby efforts Shopify is doing; they can just use this Sorbet compiler I guess.
I left Shopify late last year, so I don't know what the current internal stance is, nor do I speak for the company in any capacity.
But before I left, the strategy was to begin making inroads into typedness by attacking the most important places first (which in our case was often the inter-component abstraction boundaries). Teams were encouraged to add Sorbet annotations to their intra-component code where appropriate but it was not a blanket requirement.
Regarding JIT/CRuby/Sorbet compiler -- I don't think it's either/or. A company of Shopify's size can afford to fund work on multiple projects with overlapping goals.
After my experiments I came to the conclusion that type information would probably be better if specified in structured comments, something like TomDoc. That way type information would be had just by writing the documentation one should be writing anyway. (Two birds, one stone.) It would also make the type signatures very readable.