Live data from Hacker News

Static Typing for Ruby: Adopting Sorbet at Scale

shopify.engineering

31–40 of 72 posts

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#31
post #29
post #22

Earlier quoted context omitted.

Do you have any tips or tricks for migrating a Rails app from Sorbet `srb rbi` generated files to one using Tapioca? I was unsure exactly which bits of Sorbet rbi were still required with tapioca https://github.com/Shopify/tapioca/issues/114 We are currently using `sorbet-rails` but it appears Tapioca would be a replacement for that as well, is that correct?

Ultimately, the goal is for Tapioca to replace all `srb rbi` tooling and `sorbet-rails`. Right now, we exclusively use Tapioca for gem RBIs and we don't use any `srb rbi` tooling at Shopify. That works perfectly fine, but you don't get any `sorbet-typed` RBIs, which, right now is not a concern for us. The DSL generators are not 100% complete to fully replace `sorbet-rails` right now, but we are preparing a 1.0 releas…

Thanks for the reply!

> but you don't get any `sorbet-typed` RBIs, which, right now is not a concern for us.

Ahh ok! I think this might have been a bit I missed, cause I was commonly trying to do both which likely caused issues for me.

> The DSL generators are not 100% complete to fully replace `sorbet-rails` right now, but we are preparing a 1.0 release of the gem that should be able to do that.

Will keep my eyes open, thanks!

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#32

Earlier quoted context omitted.

The block passed to sig is evaluated in a different context, one where the local object has those methods. The methods aren't added globally, which is why you need the first method to switch the context. It's generally a good policy to avoid adding those class methods at the top level, which Sorbet does assiduously. Sig also turns into a no-op if you have runtime verification turned off, which is another good reason…

That's super informative, thank you! Can you also add a word of explanation as to how the `sig` call gets associated with the method that follows it? What ties them together, is there some static parser?

Sorbet has its own written-in-C++ parser that does the actual parsing. At runtime, the sig call basically sets a flag for the next method that is defined which hooks into it to validate that the parameters passed in are as defined, and that the return value is as expected. I believe they're delving into the dark magic in the interpreter directly, the docs are here: https://sorbet.org/docs/runtime

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#33

Earlier quoted context omitted.

The block passed to sig is evaluated in a different context, one where the local object has those methods. The methods aren't added globally, which is why you need the first method to switch the context. It's generally a good policy to avoid adding those class methods at the top level, which Sorbet does assiduously. Sig also turns into a no-op if you have runtime verification turned off, which is another good reason…

That's super informative, thank you! Can you also add a word of explanation as to how the `sig` call gets associated with the method that follows it? What ties them together, is there some static parser?

[deleted]

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#34
I've been using Sorbet for a while integrated in my SublimeText. I have never added a type signature, not even once. I just use it to prevent me from silly mistakes (like changing a variable name somewhere and breaking code downstream). The immediate red underline, which we are used to having in JS with ESLint, is such a great productivity booster.

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#35
post #34

I've been using Sorbet for a while integrated in my SublimeText. I have never added a type signature, not even once. I just use it to prevent me from silly mistakes (like changing a variable name somewhere and breaking code downstream). The immediate red underline, which we are used to having in JS with ESLint, is such a great productivity booster.

This is a great way to use Sorbet and get its benefits without having to invest 100% into typing. Great example, thanks for sharing.

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#36

Earlier quoted context omitted.

That's super informative, thank you! Can you also add a word of explanation as to how the `sig` call gets associated with the method that follows it? What ties them together, is there some static parser?

Sorbet has its own written-in-C++ parser that does the actual parsing. At runtime, the sig call basically sets a flag for the next method that is defined which hooks into it to validate that the parameters passed in are as defined, and that the return value is as expected. I believe they're delving into the dark magic in the interpreter directly, the docs are here: https://sorbet.org/docs/runtime

For the runtime, there is not much dark magic. Each type that has an `extend T::Sig` has `method_added` hooks registered, which notifies Sorbet runtime whenever a method is defined on the type. When that `method_added` hook is called, Sorbet runtime uses the sig flag that you mention to associate the `sig` with the method definition that follows it.

It is, more or less, an implementation of this idea: https://yehudakatz.com/2009/07/11/python-decorators-in-ruby/

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#37
post #36

Earlier quoted context omitted.

Sorbet has its own written-in-C++ parser that does the actual parsing. At runtime, the sig call basically sets a flag for the next method that is defined which hooks into it to validate that the parameters passed in are as defined, and that the return value is as expected. I believe they're delving into the dark magic in the interpreter directly, the docs are here: https://sorbet.org/docs/runtime

For the runtime, there is not much dark magic. Each type that has an `extend T::Sig` has `method_added` hooks registered, which notifies Sorbet runtime whenever a method is defined on the type. When that `method_added` hook is called, Sorbet runtime uses the sig flag that you mention to associate the `sig` with the method definition that follows it. It is, more or less, an implementation of this idea: https://yehudak…

Yes indeedy, I'd consider `method_added` to be pretty dark magic though :)

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#38

Earlier quoted context omitted.

The block passed to sig is evaluated in a different context, one where the local object has those methods. The methods aren't added globally, which is why you need the first method to switch the context. It's generally a good policy to avoid adding those class methods at the top level, which Sorbet does assiduously. Sig also turns into a no-op if you have runtime verification turned off, which is another good reason…

That's super informative, thank you! Can you also add a word of explanation as to how the `sig` call gets associated with the method that follows it? What ties them together, is there some static parser?

The actual signature checking is complicated, but associating the sig call with the method is pretty simple in Ruby — you just hook `method_added`. (Of course the actual implementation in something like Sorbet is a lot more sophisticated than just `def method_added`, but that's the basics of how you make a method call alter the next method definition.)

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#39
post #16
post #9

Earlier quoted context omitted.

Having used Sorbet, one thing immediately noticeable is that it's incredibly verbose due to needing to be valid ruby syntax. Was there any developer pushback on that? Also, maybe I missed it, but Sorbet has a very fleshed out plugin for VSCode but that's about it. How was the experience getting people who don't use VSCode to integrate it into their workflow?

There was definitely some general suspicion when we first introduced Sorbet. However, there were also some early adopters who didn't mind the syntax but really wanted the benefits. That's why we didn't push for types adoption, we allowed teams to adopt (or not) at their own pace. Once people saw the benefits, they wanted more of it. Syntax also stopped being a huge concern. Quoting from the blogpost: > - Developers g…

Dmitry here, from Stripe. One of founding members of Sorbet(though I no longer work on it anymore).

Story that Ufuk shares is common.

We saw this process repeat in many companies, Stripe, Shopify and many others - folks are initially bothered with verbosity of `sig` syntax, but as the company starts using it in practice stop being bothered pretty quikcly. It happens even faster now that IDE integration allows to auto-complete entire signature and can in most cases correctly guess the types of arguments & result type. You rarely type `sig`s yourself.

The common internal asks at Stripe are about even better IDE support, new features & etc and that's where most of investments are. Well, and and obviously performance. Sorbet was already very fast and we intend to keep it fast as our huge codebase grows.

Re: Static Typing for Ruby: Adopting Sorbet at Scale

#40

What makes Ruby so irreplaceable? Why struggle to make it something it's not when you could pick an existing statically typed language and build your system? Also how is Ruby a safe language for financial transactions when an engineer can hijack a running process and change memory without leaving a trace

> hijack a running process and change memory without leaving a trace Doesn't sound like a Ruby problem.

No but, Ruby makes it trivial. No decompilations, no assembly, no debuggers necessary. Drop into an irb in a running process, change stuff and get out in seconds
Post reply on HN