Sorbet has no way to ignore an error on a specific line with a magic comment. This is different from all other gradual static type checkers I know about:
# type: ignore
When I first joined the team, I was skeptical. But having seen it play out in practice, it’s actually worked great.
Instead of ignore comments, Sorbet has
T.unsafe, which accepts
anything and returns it unchanged (so for example
3). The trick is that it forces Sorbet to forget the
type of the input statically. This confers the power to silence most
errors. For example:
In this example, Sorbet knows that calling
+ on an Integer with a
String would raise an exception at runtime, and so it reports a static
type error. But wrapping the
1 in a call to
T.unsafe causes Sorbet
to think that the expression
T.unsafe(1) has type
like for all untyped code, Sorbet admits the addition.
All Sorbet-typed Ruby programs must grapple with
Sorbet user has to learn how it works and what the tradeoffs of using it
are. In particular, that
T.untyped is viral. Given a variable that’s
T.untyped, all method calls on that variable will also be untyped:
In this example
x enters the method as
T.untyped, so calling the
.even? propagates the
y. Then again because
y is untyped, calling1
! on it propgates the
z. There are plenty of reasons to both embrace and avoid
T.untyped in a type system but the point is: Sorbet’s type system
already has it.
T.untyped as the way to silence errors plays nicely with
everything else in Sorbet:
Hover and jump to definition become tools to track down the source of silenced errors.
Errors are effectively silenced at the source of the error. There are no errors downstream that only show up because an error was silenced earlier.
We plan to eventually build a tool to show which parts of a file are untyped (to see things like which methods don’t have signatures). That tool will trivially take suppressed errors into account.
The Sorbet docs bill
T.untyped as the way to “turn off the
type system.” By reusing
T.untyped to supress errors, silencing one
error means silencing them all, which is a win for simplicity.
Did you know that
!xin Ruby is syntactic sugar for
x.!(), which means that you can override
!to make it do something else?↩