Jake Zimmerman
April 23, 2025
Semantics are about conveying the thoughts in your head
Cueball, likely getting sucked into a debate about type syntax.
Agenda:
:jez-type-safety:
Jake Zimmerman @jez
working on Sorbet for almost 7 years
at Stripe since 2016/2017
mid 2017: ~750 people, ~300 engineers
Responses to survey on developer productivity (pick three):
“What are the top 1-2 things we could do to make you more productive?”
mono-repoing all the things; better, more intuitive code/documentation (clearer interfaces, static typing, stronger assurances from linting)
static types / less magic in [Stripe’s Ruby codebase]
builds being faster, tests on branches passing meaning you wont break master, static types in [Stripe’s Ruby codebase]
It wasn’t part of the project to convince people to want static typing.
…They convinced us!
The team evaluated various approaches:
🙅♂️ Rewriting to a typed language
→ Too much work
🙅♂️ RDL
→ Not static enough
🙅♂️ TypedRuby
→ Buggy
✅ write our own from scratch
Breaks compatibility
TypeScript: gave up “save file, reload page” ages ago
Ruby: no one uses transpilers
linters, syntax highlighting, code formatting, backtraces, IDEs would all break
prevents gradual adoption by open source community
Everyone builds it eventually, but complementary
“Only separate files” is not enough: you need inline type assertions
Unique selling point: complete freedom in syntax design
Comments are static only…
Stripe wanted static AND runtime!
With a sufficient number of users of an API,
it does not matter what you promise in the contract:
all observable behaviors of your system
will be depended on by somebody.
declare_methdod
becomes sig
Started as Function Annotations
Later standardized Type Hints using Function Annotations
Pros
Cons
Definitely not viable for Sorbet in 2017!
DSL approach is a close approximation:
🧐 would require monkey patch
🧐 sometimes already conflicts with other methods
Integer?
instead of
T.nilable(Integer)
(Integer) -> String
instead of
T.proc.params(arg0: Integer).returns(String)
|
and
&
without monkey patches
It can’t break compatibility
Must support runtime checking too
Could probably go further with optional monkey patches
Think about forward references
Not perfect (doesn’t solve the T.let
use case for inline
assertions), but really good!
→ We can always keep improving Sorbet
→ It’s an exciting time for types in Ruby itself
(I have some stickers!)