3 ms·
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 n
by jaggederest 6y ago
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 not to call params right away, because (in ruby) you can ignore everything in the block if the block is not called, sort of like a debug macro in C, but you can't do that with a method that is called - it must evaluate its parameters.
- aerovistae 6y agoThat'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?
- jaggederest 6y agoSorbet 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 https://sorbet.org/docs/runtime
- ufuk 6y agoFor 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/ https://yehudakatz.com/2009/07/11/python-decorators-in-ruby/
- jaggederest 6y agoYes indeedy, I'd consider `method_added` to be pretty dark magic though :)
- deleted 6y ago[deleted]
- chc 6y agoThe 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.)