Today I learned that Sorbet interfaces do some magic to override how Ruby module and method overloading usually works. This is great, lets take a look!
We had a base class lets call it SomeBaseClass
and it implemented a method like api_options
.
So we had the following and OurClass#api_options
was 'correctly' using the
implementation from SomeBaseClass
include ApiInterface
end
But what was interesting is ApiInterface
was defined to need a
api_options
method, which looks like this
sig { abstract.returns(ApiOptions) }
; end
Without all the Sorbet stuff in the sig
that's an empty method definition which would
just return nil
everytime. Without Sorbet we'd expect OurClass#api_options
to return
nil since this version would be the last one defined.
However, Sorbet is doing the 'right' thing and calling the actual implementation from our base class! It kind of has to, or else it's interfaces would be hard to work with. But its good to confirm, and write down for next time I run into this!
I dug a bit and found some code to replace a method and some to call the original implementation, so I assume some combination of these is how Sorbet pulls off this trick. Maybe I'll dig deeper and turn this into a full post in the future.
My weekly newsletter tailored at developers who are eager to grow with me!
Every week will be unique, but expect topics focusing around Web Development and Rust