Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Good Enough Types: Heuristic Type Inference for...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Shia Shia
April 23, 2026

Good Enough Types: Heuristic Type Inference for Ruby

RubyKaigi 2026 Day 3

Avatar for Shia

Shia

April 23, 2026

More Decks by Shia

Other Decks in Technology

Transcript

  1. It’s a try to provide "good enough type information" without

    writing types. supported by Ruby Association Grant type-guessr 9
  2. Landscape of type support tools for Ruby 10 How much

    depends on type declarations Steep / Sorbet Ruby LSP Guessed type TypeProf solargraph Quality of provided type information
  3. Landscape of type support tools for Ruby 11 Steep /

    Sorbet Ruby LSP Guessed type TypeProf solargraph Require type declarations How much depends on type declarations Quality of provided type information
  4. Landscape of type support tools for Ruby 12 Steep /

    Sorbet Ruby LSP Guessed type TypeProf solargraph Reasonable type inference Haven't heard of large-scale adoption Depends on gem-side RBS availability How much depends on type declarations Quality of provided type information
  5. Landscape of type support tools for Ruby 13 Ruby LSP

    Guessed type TypeProf solargraph Close to what I want Lack of Hash, Array inside info Overlaps with ruby-lsp Steep / Sorbet How much depends on type declarations Quality of provided type information
  6. Landscape of type support tools for Ruby 14 Ruby LSP

    Guessed type TypeProf solargraph Support simple inference like: var name “user” to “User” class Steep / Sorbet How much depends on type declarations Quality of provided type information
  7. Landscape of type support tools for Ruby 15 Ruby LSP

    Guessed type TypeProf solargraph Here!!!! Steep / Sorbet How much depends on type declarations Quality of provided type information
  8. Duck typing: "If it can quack, treat it as a

    duck" - Ignore the type. Only behavior (methods) matters - behavior as a type Approach - Duck typing 18
  9. What we will do: "quack() is called on this object.

    The only class with this is… Duck class" - Infer the type from observed behavior. - type from behavior. Approach - Duck typing inspired heuristic 19
  10. Approach - Will this work? 23 Identify type from how

    code is used (list of called methods). Experiment on 3 large Rails projects at work: - Collect all method calls per variable / argument - Filter candidates which have all called methods per var / arg - Count vars / args that get only one candidate. -> achieved ~10-20% estimation.
  11. Most Ruby "object" inherit "Object" class. so, Assume that some

    objects receive "==", "to_s", then it will match all registered Class, 60% of slow inferences came from here. Exception: instance methods of "Object" 30
  12. Exception: Object 31 Most Ruby "object" inherit "Object" class. so,

    Assume that some objects receive "==", "to_s", then it will match all registered Class, 60% of slow inferences came from here. Solution: Excludes instance methods of "Object" class on duck typing heuristic. End with "untyped" if node only receives "Object" methods ASAP.
  13. - To concentrate on inference logic, not lsp server implementation

    - Just providing type info, ruby-lsp will handle text on hover, candidate on autocompletion, def jump… - Get methods generated by DSL from other add-on, such as ruby-lsp-rails - …or so I thought. Impl as ruby-lsp add on 42
  14. - Don’t infer at index time - Do inference when

    requested with cache - some gems are very slow to infer/parse as they have too many files. so with gems: - Collect constant and its method on indexing time. - Building IR nodes, inferring lazy. Lazy Inference 46
  15. Everyone knows DSL support is hard for type inference on

    Ruby. Let’s see the patterns which makes inference hard with activerecord, well known gem to you. DSL support… is hard 49
  16. rbs_rails and tapioca do essentially the same thing: - Run

    project, and get the needed information at runtime - Write out concrete type information to RBS based on that How do existing tools handle this? 52
  17. ruby-lsp-rails does the same thing, too. Boots a Rails process

    via "bin/rails" and dynamically dispatches from there(via RuntimeClient). Class methods land in the code index, but model attribute info doesn't. It fetches information when requested. How do existing tools handle this? 53
  18. type-guessr's Approach type-guessr doesn't want users to write types, and

    ideally doesn't want to add RBS to the codebase. - Decide to embed ActiveRecord-aware logic internally (experimental) - trust ActiveRecord's interface stability for now - Eventually we want a registration API to externalize this — future work. - or… 54
  19. Current implementation 55 For activerecord, it has 2 parts: -

    Queries the Rails runtime - column info, associations, enums, scopes… - Base on above, generate methods and register those to index
  20. Speed 61 - For our company's Rails apps: startup under

    20s with ruby-lsp. Inference under 2s without cache. Under 1s when warm. - "An LSP must not interfere with editor operations" - Most inference done in 100-200ms - It's only occasionally slow… Note: Benchmarks and coverage reports are in the repo
  21. - Weak against small methods - Getting the correct method

    list is critical, otherwise everything falls into untyped - Diagnostic is hard - Information to validate and information to aid inference are tangled together — still figuring this out - First step might be just to give warning when there is no matched constants? Limitation 62
  22. MCP Server We live in AI age, so AI should

    be considered as a user of type-guessr. Published as an MCP (Model Context Protocol) server: 3 tools - infer_type - get_method_signature - search_methods But, wait, do we really need it? 64
  23. Target: - plain Claude code(CC) - CC with ruby-lsp -

    CC with ruby-lsp with prompt encourage to use it - CC with type-guessr MCP - CC with type-guessr MCP with prompt encourage to use it Experiment for fun 65
  24. Tasks: - 1. Trace method call chain → return type

    - 2. Resolve AR column / association types - 3. Detect DSL-generated methods (scope, enum) - 4. Disambiguate same-name methods across classes - 5. Infer Hash Record type - 6. Follow methods through include / extend - 7. Fix plan for method on one side of Union 66 Experiment for fun
  25. - You can extract sufficient information from code without writing

    types - "Good Enough" has real value…? - at least to me - try it: "gem install type-guessr" (& "gem install ruby-lsp") - https://github.com/riseshia/type-guessr Conclusion 68