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

Ruby programming with types in action

Ruby programming with types in action

RubyKaigi 2022 -- Tsu, Mie, Japan
September 10, 2022

Soutaro Matsumoto

September 10, 2022
Tweet

More Decks by Soutaro Matsumoto

Other Decks in Programming

Transcript

  1. Soutaro Matsumoto (@soutaro)
    Ruby programming with types
    in action
    This work by RubyKaigi 2022 Team is licensed under a Creative Commons Attribution 4.0 Unported License.
    #BF4545 #B8A562 #755B8E #4E6994 #41414F #2C2C31 UFYUDPMPS

    View Slide

  2. @soutaro
    • Developer of Steep & RBS

    • Ruby committer

    • Working for Square Block
    Soutaro Matsumoto

    View Slide

  3. RBS & Steep
    • We have
    fi
    ve talks related to RBS/Steep this year

    • Generating RBS is big topic

    • How can we use the type de
    fi
    nitions?

    • Show people the types instead of callseq

    • Type checking! 💪

    View Slide

  4. RBS 2.7.0.pre.1
    Updates since Ruby 3.1 (RBS 2.0)
    • Type of self in blocks/procs (Steep 1.2 will support)

    • Batch prototype (RBS 2.5)

    • $ rbs prototype rb --out-dir=sig/app app


    • RDoc plugin (Supported by Google Summer of Code)

    • $ rdoc sig
    def foo: { () [self: String] -> void } -> void
    def instance_eval: [A] { () [self: self] -> A } -> A
    $ gem install rbs --pre

    View Slide

  5. Type checking benefits
    When we have a typed Ruby code base
    • Understanding code

    • API documentation

    • Adding a new feature

    • Refactoring the feature

    View Slide

  6. Demo
    What can we do with typed Ruby code
    • Hover

    • Goto de
    fi
    nition

    • Completion

    • Type errors

    View Slide

  7. Demo

    View Slide

  8. Demo 2
    Getting started with Steep
    1. Setup

    2. Generate RBS
    fi
    le prototypes

    3. Run type checker

    4. Add more types

    View Slide

  9. Demo app
    • Point-of-sale app

    • Models

    • Order

    • OrderItem

    • CashPayment

    • CardPayment

    View Slide

  10. Demo app
    • Point-of-sale app

    • Models

    • Order

    • OrderItem

    • CashPayment

    • CardPayment

    View Slide

  11. Demo app
    • Point-of-sale app

    • Models

    • Order

    • OrderItem

    • CashPayment

    • CardPayment

    View Slide

  12. Demo 2

    View Slide

  13. Focus on the part you work on
    • You don't have to
    fi
    x all of the type errors when you start

    • Give types to the related part as you need

    • Type checking a few small
    fi
    les would be good for exercise
    Detected 1759 problems from 85 files

    View Slide

  14. Focus on the part you work on
    • You don't have to
    fi
    x all of the type errors when you start

    • Give types to the related part as you need

    • Type checking a few small
    fi
    les would be good for exercise
    Detected 1759 problems from 85 files

    View Slide

  15. Make your code safe against nil
    • The only one way to handle nil safely: test every time before using it

    • Optional type helps you
    # @type var order: Order?


    if order = Order.find_by(id: params[:id])


    order.update(...)


    else


    render status: :not_found


    end
    # def sample: () -> Element?


    unless array.empty?


    random = array.sample or raise


    end
    Do something else if nil It cannot happen

    View Slide

  16. Help Steep type check your code
    # @type var out_dir: Pathname?


    out_dir = nil


    # @type var pairs: Array[[String, Integer]]


    pairs = []
    Declare the variable types
    Cast to untyped or skip type checking 1 + (_ = "")


    __skip__ = 1 + ""
    MoneyData = Struct.new(:currency, :amount) do


    # @implements MoneyData


    def exchange_to(currency, rate)
    Support meta-programming

    View Slide

  17. Writing new code
    • Type checking existing code is 😫

    • You know there is no critical bug there

    • Steep will detect minor problems that forces you add workarounds

    • Many e
    ff
    orts, little bene
    fi
    ts

    • Let's write new code with Steep 💪

    • There must be unknown bugs

    View Slide

  18. Demo 3
    Adding new feature with types
    • De
    fi
    ning APIs in RBS

    • Writing implementation with type checker

    View Slide

  19. Add search feature
    "ca
    ff
    e latte"

    View Slide

  20. Add search feature
    "ca
    ff
    e latte" before:2022-08-01 paid-by:cash

    View Slide

  21. Demo 3

    View Slide

  22. Inheritance vs union types
    • Choose one that is more suitable for the problem

    • Steep helps you keep case-when safe and up to date
    # @type var query: Query::Base


    query.build_relation()
    # @type var query: Query::Name | Query::Before | Quer


    case query


    when Query::Name


    ...


    when Query::Before


    ...


    when Query::PaidBy


    ...


    end
    Inheritance Union types

    View Slide

  23. Inheritance vs union types
    • Inheritance 㱻 method call, union types 㱻 case-when

    • Known set of data types → union types + case-when

    Unknown set of data types → inheritance + method call

    • Expression problem

    • Union types are generalization of optional types

    • Integer? == Integer | nil

    • Union types help you enumerate all cases

    View Slide

  24. Working with types
    • Types are abstraction of your code

    • Easier to write/change than implementation/tests

    • Validates consistencies between components unlike design docs

    • Type de
    fi
    nitions and implementation are iterative

    • Write types → write code → types → code → ...
    App code Tests RBS
    Design docs

    Whiteboard
    Detailed Abstract

    View Slide

  25. Working with types
    • Types are abstraction of your code

    • Easier to write/change than implementation/tests

    • Validates consistencies between components unlike design docs

    • Type de
    fi
    nitions and implementation are iterative

    • Write types → write code → types → code → ...
    App code Tests RBS
    Design docs

    Whiteboard
    Detailed Abstract

    View Slide

  26. Can I do it with RubyMine?
    • RubyMine has limited support for Steep

    • But, it provides another type checker integrated with RBS, and you can
    develop Ruby programs with types using RubyMine

    View Slide

  27. Recap
    • More bene
    fi
    t from types when you write new code

    • Writing types and implementation

    • Anti-patterns without types can be a best practice

    • Easier trial and error with types than with implementation

    View Slide