restricting Do not think they’ll ever need them They think they are less likely to have an accident https://www.bbc.com/news/blogs-magazine-monitor-29416372
checks by adding a sig # typed: true class User extend(T::Sig) sig do params(user_hash: T::Hash[Symbol, String]) .returns(String) end def self.name_from_hash(user_hash) user_hash.fetch(:name, "[No Name]") end # Not checked def age 45 end end User.name_from_hash(name: "Ufuk") User.new.age 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
that keeps on giving: # typed: true class User def age 45 end end user = User.new user.age #=> 45 user.country # Error: Method `country` does not exist on `User` untyped_user = T.let(User.new, T.untyped) untyped_user.country # No errors city = untyped_user.country.capital # No errors, `city` is also `T.untyped` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# typed: true class A define_method(:foo) { puts 'In A#foo' } define_singleton_method(:bar) { puts 'In A.bar' } end class B < A bar # => Method `bar` does not exist on `T.class_of(B)` T.unsafe(self).bar # ok end 1 2 3 4 5 6 7 8 9 10 11
makes them nilable. # typed: true class User extend(T::Sig) sig { params(birth_date: T.nilable(Date)).returns(Integer) } def age(birth_date) # Error: Returning value that does not conform to method result type if birth_date calculate_age(birth_date) end end sig { params(birth_date: Date).returns(Integer) } def calculate_age(birth_date) # Do hard date math end end 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
true class User extend(T::Sig) sig { params(birth_date: T.nilable(Date)).returns(Integer) } def age(birth_date) if birth_date calculate_age(birth_date) else 45 end end sig { params(birth_date: Date).returns(Integer) } def calculate_age(birth_date) # Do hard date math end end 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
static type checking sorbet runtime used for runtime type checking, but not in production. tapioca used for RBI generation from gems rubocop sorbet to enforce certain rules spoom to encapsulate Sorbet operations Releasing custom tooling back to community as open-source rubocop sorbet - Open-source, announced tapioca - Open-source, announced spoom - Open-source, announced
all constants to resolve. Sorbet has no idea about the constants exported from gems. srb init (along with sorbet typed repo) does a decent enough job but we wanted better
ile, . runs Sorbet over each gem’s source code, . uses re lection to discover ancestors, mixins, methods and subconstants . generates a separate RBI for each gem tagged with its version.
tests or CI” “Allowed us to write less tests” “Both static and runtime typecheckers caught errors not caught by tests alone” “Easier to use in new code”
tests or CI” “Allowed us to write less tests” “Both static and runtime typecheckers caught errors not caught by tests alone” “Easier to use in new code” “Improves code quality, makes you design better code”
tests or CI” “Allowed us to write less tests” “Both static and runtime typecheckers caught errors not caught by tests alone” “Easier to use in new code” “Improves code quality, makes you design better code” “Living documentation of the public contract of your code”
visibility” “It is not DRY” “Types can get hard to write in more complex cases” “Hard to add types to existing code” “Rails and other metaprogramming is not fully functional yet”