• Bug detection before execution • Completion and document in IDE … with no type annotation in code! (Ruby 3 Type Challenge) 2 42 + "str" Is this a bug? 42.ti| Do you mean: 42.times {|i| | }
def inc: (Integer) -> Integer ① Type Signature Format (RBS) # app.rb def inc(n) n+1 end Ruby code ② Type Inference (ruby-type-profiler) ③ Type Check (Steep, Sorbet, RDL, …)
app.rbs 42.ti| 42 + "str" Is this a bug? Do you mean: 42.times {|i| | } ② Type Inference • Generate an RBS prototype • Simply check the code ③ Type Checker • Verify .rb and .rbs • Serve as LSP server You can also write RBS manually if you want Type-guided linter Dynamic type checker More dedicated dev. environments Monitor and Harness Ruby code in run-time Code formatter by leveraging types Rubymine, Tabnine, and other development tools may use type information https://github.com/pocke/rubocop-typed https://github.com/ruby/rbs/blob/master/ lib/rbs/test/type_check.rb RBS may inspire other dreams Today we talk about ①RBS
an RBS prototype by gathering what types a method accepts and returns 6 def foo(n) n.to_s end foo(42) Integer (not 42) String (not "42") def foo: (Integer) -> String
historical reason • The initial version was runtime analysis (profiling) • Now it is a bit confusing with a normal profiler •Invite suggestions for the name • Should it start with "S"? (Steep, Sorbet, …) 7
(per-method) analysis • Can't handle unannotated method parameter well • … especially when there are many classes that respond to foo 8 def f(x) x.foo end What type is "x"? class Foo def foo; ...; end end class Bar def foo; ...; end end class Baz def foo; ...; end end ...
→ Avoid this 2. Infer type based on its usage → Too strict or too conservative • foo must be unique • or, structural type inference? 3. Use "inter-procedural" analysis • Pros: More powerful analysis • Cons: Slow and hard to control (Challenging) 9 def f(x: Foo) x.foo end def f(x) x.foo end f(Foo.new) "x" is a Foo! def f(x) x.foo end "x" is an object that responds to foo that accepts no argument and returns the same type of a return value of this method
linter for Ruby (~2000 LoC) • It has "hand-written" RBS • Analysis time < 30 sec. • Note: It requires many libraries which have no RBS • activesupport, concurrent-ruby, cgi, optparse, etc. • Type Profiler analyzed not only Goodcheck but also them • In future, we expect they have own RBS • Type Profiler can use RBS instead of the code itself 15
entry point •Analysis time < 1 sec. 18 https://bestgems.org/ require_relative "lib/diff/lcs" class T; end Diff::LCS.diff([T.new]+[T.new], [T.new]+[T.new]) {}
program (if needed) 2. Apply Type Profiler 3. Partially write RBS for wrong-guessed methods 4. Re-apply Type Profiler 21 lib.rb app.rb Type Profiler lib.rbs (may include wrong guesses) partial RBS for difficult methods lib.rbs (final) ① ② ③ ④ "Partial RBS specification" has been implemented
Import Array and Hash methods from RBS • Type variable • Support Enumerable, Enumerator, and Struct • Support global variables • Improve flow-sensitive analysis • Improve analysis performance • Fix many, many bugs 24
plain Ruby code • Support partial RBS specification • Write document and release a gem • Continue to experiment, improve, etc, etc. • After the release: Support Sinatra app, Rails app… • Maybe need dedicated hard-coding for the frameworks • Concern is almost a language extension • ActiveRecord is super-meta feature • Please go easy on 🙏 25