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

You and Your Type[s] Aren't Welcome Here

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

You and Your Type[s] Aren't Welcome Here

Thinking in a type-driven fashion doesn't require throwing Ruby away. Here are some examples of how types can make our Ruby programs better, while still looking and feeling like Ruby.

Avatar for Andy Nicholson

Andy Nicholson

February 10, 2017

Other Decks in Programming

Transcript

  1. I made up the term ‘object- oriented,’ and I can

    tell you I didn't have C++ in mind. — Alan Kay, OOPSLA ’97
  2. let mut x = 5; // Rust final double Tau

    = 6.2831852; // Java VERSION = '5.6.28'; // PHP
  3. var value : integer; pointer_to_integer: ^integer; begin value := 42;

    pointer_to_integer := @value; end. {* Pascal *}
  4. public class Pet { private String name; private Person owner;

    public Pet(String name, Person owner) { this.name = name; this.owner = owner; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person getOwner() { return owner; } public void setOwner(Person owner) { this.owner = owner; } }
  5. If a method responds to the methods we expect it

    to, it’s probably* the right type.
  6. def print_items(collection) collection.each do |item| puts " #{item[:code].upcase}: #{item[:price]}" end

    end def process_report(data) # ... # ... print_items(data) end # What happens here? process_report([{}])
  7. def print_items(collection) collection.each do |items| items = Hash(items) puts "

    #{collection.fetch(:code).upcase}: #{collection[:price]}" end end
  8. process_report([ [] ]) # /tmp/reporting.rb:4:in `fetch': key not found: :code

    (KeyError) process_report([ {} ]) # /tmp/reporting.rb:4:in `fetch': key not found: :code (KeyError) process_report( [ [1] ]) # /tmp/reporting.rb:3:in `Hash': can't convert Array into Hash (TypeError)
  9. class Plant def initialize(code:, price:) # … end attr_reader :code,

    :price def to_hash { code: code, price: price } end end process_report([Plant.new(code: "NOT_A_POT_JOKE", price: 419) ]) # => outputs "NOT_A_POT_JOKE: 419"
  10. Curious? • Confident Ruby, by Avdi Grimm ( http://confidentruby.com/ )

    • contracts.ruby ( http://github.com/egonSchiele/contracts.ruby ) • dry-types ( http://github.com/dry-rb/ )
  11. begin result = operation_that_may_fail_1(data) result = operation_that_may_fail_2(result) result = operation_that_may_fail_3(result)

    rescue Failure1 => f # … rescue Failure2 => f2 # … rescue Failure3 => f3 # … end
  12. result = nil begin result = operation_that_may_fail_1(data) rescue Failure1 =>

    f return "Unable to perform step 1: #{e.message}" end begin result = operation_that_may_fail_2(result) rescue Failure1 => f2 return "Step 2 failed " end begin result = operation_that_may_fail_3(result) rescue Failure1 => f3 return "" end
  13. Yuk

  14. r = Try() { operation_that_may_fail1(data) } .bind { |result| operation_that_may_fail2(result)

    } .bind { |result| operation_that_may_fail3(result) } if r.success? r.value else raise res.exception # or log, or whatever end