Successfully reported this slideshow.

Type checking in Ruby - Mykhailo Bortnyk | Ruby Meditation 31

0

Share

1 of 19
1 of 19

Type checking in Ruby - Mykhailo Bortnyk | Ruby Meditation 31

0

Share

Download to read offline

Video of the talk: https://youtu.be/-1-74zn-ZF4

Talk of Mykhailo Bortnyk, Ruby developer, at Ruby Meditation #31 Online, 23.01.2021
Next conference - http://www.rubymeditation.com/

Description:
After Sorbet, Ruby team started to develop homebrew type checking system. We’ll take a look on type checking tools in Ruby, review pros and cons of all of them. We are going to do some type-checking tasks and experiments and consider if type checking in Ruby is ready for production usage.

Announcements and conference materials https://www.fb.me/RubyMeditation
News https://twitter.com/RubyMeditation
Photos https://www.instagram.com/RubyMeditation
The stream of Ruby conferences (not just ours) https://t.me/RubyMeditation

Video of the talk: https://youtu.be/-1-74zn-ZF4

Talk of Mykhailo Bortnyk, Ruby developer, at Ruby Meditation #31 Online, 23.01.2021
Next conference - http://www.rubymeditation.com/

Description:
After Sorbet, Ruby team started to develop homebrew type checking system. We’ll take a look on type checking tools in Ruby, review pros and cons of all of them. We are going to do some type-checking tasks and experiments and consider if type checking in Ruby is ready for production usage.

Announcements and conference materials https://www.fb.me/RubyMeditation
News https://twitter.com/RubyMeditation
Photos https://www.instagram.com/RubyMeditation
The stream of Ruby conferences (not just ours) https://t.me/RubyMeditation

More Related Content

More from Ruby Meditation

Related Books

Free with a 14 day trial from Scribd

See all

Type checking in Ruby - Mykhailo Bortnyk | Ruby Meditation 31

  1. 1. Type checking in Ruby A brief review of modern type-checking tools
  2. 2. Situation with type checking
  3. 3. Situation with type checking ● Type checkers ○ Sorbet ○ Steep ○ RBS tests ● Type signatures ○ Sorbet RBI ○ RBS ● Type signatures generators ○ Sorbet ○ RBS prototype ○ Typeprof
  4. 4. RBS toolset
  5. 5. RBS commands ● ast - prints JSON representation of AST of loaded environment ● list - lists classes, modules and signatures in type system ● ancestors - shows ancestors of given class or module ● methods - shows methods defined in given class or module ● method - shows type signature and information about given method ● validate - validates RBS files ● constant - resolves constant based on RBS ● paths - list of included paths of type signatures ● prototype - generates prototypes of RBS signatures ● vendor - vendors signatures inside project directory ● parse - parses given signature files and outputs errors ● test - to observe tests to ensure signatures are correct
  6. 6. class Calculator attr_reader :arg1, :arg2 def initialize(arg1, arg2) @arg1 = arg1 @arg2 = arg2 end def add; arg1 + arg2; end def mul; arg1 * arg2; end def div; arg1 / arg2; end def sub; arg1 / arg2; end def call(method_name) case method_name when :add then add when :mul then mul when :div then div when :sub then sub end end end First signature.RB try class Calculator attr_reader arg1: untyped attr_reader arg2: untyped def initialize: (untyped arg1, untyped arg2) -> untyped def add: () -> untyped def mul: () -> untyped def div: () -> untyped def sub: () -> untyped def call: (untyped method_name) -> untyped end
  7. 7. class Calculator attr_reader :arg1, :arg2 def initialize(arg1, arg2) @arg1 = arg1 @arg2 = arg2 end def add; arg1 + arg2; end def mul; arg1 * arg2; end def div; arg1 / arg2; end def sub; arg1 / arg2; end def call(method_name) case method_name when :add then add when :mul then mul when :div then div when :sub then sub end end end First signature.Runtime try class Calculator public def add: () -> untyped def arg1: () -> untyped def arg2: () -> untyped def call: (untyped method_name) -> untyped def div: () -> untyped def mul: () -> untyped def sub: () -> untyped private def initialize: (untyped arg1, untyped arg2) -> untyped end
  8. 8. # typed: true class Test extend T::Sig sig {params(x: Integer).void} def foo(x) puts(x + 1) end end Migration from Sorbet signatures class Test def foo: (Integer x) -> void end
  9. 9. VariadicUntypedFunction = T.type_alias { Proc } AssociationCallback = T.type_alias do T.nilable( T.any( Symbol, String, T.proc.void, Proc, T::Array[T.any(Symbol, Proc, T.proc.void)] ) ) end Migration from Sorbet signatures,complex example # converted example VariadicUntypedFunction: untyped AssociationCallback: untyped # real conversion type variadic_untyped_function = Proc type association_callback = (Symbol | String | void | Proc | Array[(Symbol | Proc | void)])?
  10. 10. class Calculator attr_reader :arg1, :arg2 def initialize(arg1, arg2) @arg1 = arg1 @arg2 = arg2 end def add; arg1 + arg2; end def mul; arg1 * arg2; end def div; arg1 / arg2; end def sub; arg1 / arg2; end def call(method_name) case method_name when :add then add when :mul then mul when :div then div when :sub then sub end end end First signature.Merged example class Calculator public type result = Integer | Float attr_reader arg1: result attr_reader arg2: result def add: () -> result def mul: () -> result def div: () -> result def sub: () -> result def call: (Symbol method_name) -> result private def initialize: (result arg1, result arg2) -> result end
  11. 11. Typeprof Typeprof is a custom-built interpreter which creates type signatures based on abstract execution. Non-reachable methods produce untyped stubs. Specifics: ● Needs entry point ● Meta-programming is only partially supported ● Doesn’t handle metaclasses ● Supports only Array and Hash container types
  12. 12. Deeper look on container types class Stub def initialize @x = ["Container"] @y = { order: 1, value: "Some value" } end def foo @x end def bar @y end end p Stub.new.foo p Stub.new.bar # Revealed types # test_4.rb:16 #=> [String] # test_4.rb:17 #=> {order: Integer, value: String} # Classes class Stub @x: [String] @y: {order: Integer, value: String} def initialize: -> {order: Integer, value: String} def foo: -> [String] def bar: -> {order: Integer, value: String} end # The maximum depth of nested arrays and hashes is limited to 5.
  13. 13. Try it online! https://mame.github.io/typeprof-playground
  14. 14. How to build your signatures ● Generate stubs with rbs prototype rb file_name.rb ● Execute typeprof with some Kernel#p calls to reveal types ● Run prototyping by rbs prototype runtime ● Add missing, correct signatures
  15. 15. Type checking
  16. 16. Steps to work with steep ● steep init to generate Steepfile ● steep check to perform typechecks ● steep stats to show type stats target :lib do signature "sig" check "lib" # Directory name check "Gemfile" # File name # ignore "lib/templates/*.rb" # library "pathname", "set" # Standard libraries # library "strong_json" # Gems end target :spec do signature "sig", "sig-private" check "spec" # library "pathname", "set" # Standaard libraries # library "rspec" end
  17. 17. Steps to work with steep ● steep init to generate Steepfile ● steep check to perform typechecks ● steep stats to show type stats target :lib do signature "sig" check "lib" # Directory name check "Gemfile" # File name # ignore "lib/templates/*.rb" # library "pathname", "set" # Standard libraries # library "strong_json" # Gems end target :spec do signature "sig", "sig-private" check "spec" # library "pathname", "set" # Standaard libraries # library "rspec" end
  18. 18. Can I use it on production? ● Well, you can. It promises a lot of fun ● Lack of proper metaprogramming support ● A lot of signatures generation tools, no perfect ● Demands explicitness ● Dislikes splats ● Use it on your own risk
  19. 19. thanks! Any questions?

×