Checking Your Types
•refresh ourselves on type systems
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
4.
Checking Your Types
•refresh ourselves on type systems
• types in Ruby
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
5.
Checking Your Types
•refresh ourselves on type systems
• types in Ruby
• What's new in Ruby 3
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
6.
Checking Your Types
•refresh ourselves on type systems
• types in Ruby
• What's new in Ruby 3
• Typecheckers
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
7.
Checking Your Types
•refresh ourselves on type systems
• types in Ruby
• What's new in Ruby 3
• Typecheckers
• Examples!
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
8.
What are types?
Javascript
>>num = 2
2
>> console.log(typeof num);
number
C
char string[] = "C strings are arrays of characters";
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
9.
Static vs. Dynamic
Whendo we know what types we're working with?
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Static
• Knows typesbeforehand.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
13.
Static
• Knows typesbeforehand.
• As a party host, knows the number of guests to cater for.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Dynamic
• Knows typeswhen they show up.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
17.
Dynamic
• Knows typeswhen they show up.
• Probably easier to crash their party /
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Strong vs. WeakTypes
"...whenever an object is passed from a calling function to a called
function, its type must be compatible with the type declared in the
called function."
- Liskov & S. Zilles, 19741
1
Liskov, B; Zilles, S (1974). "Programming with abstract data types". ACM SIGPLAN Notices. 9 (4): 50–59.
CiteSeerX 10.1.1.136.3043. doi:10.1145/942572.807045.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
20.
Strongly typed language
>>num = 2
2
>> num[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable
>> num + "hello"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
21.
Weakly typed language
>>num = 2
2
// It will always try:
>> num[0]
undefined
// But sometimes this means strange things can happen:
>> num + "hello"
"2hello"
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Numeric conversion
2 +26.3
=> 28.3
# The above works because the `coerce` method is called before adding:
2.coerce(26.3)
=> [26.3, 2.0]
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
30.
!
Why add typesto Ruby? Isn't this making
the language less expressive?
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
31.
!
Why add typesto Ruby? Isn't this making the
language less expressive?
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
32.
!
Why add typesto Ruby? Isn't this making the
language less expressive?
• Improved tooling means less mental overhead
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
33.
!
Why add typesto Ruby? Isn't this making the
language less expressive?
• Improved tooling means less mental overhead
• Ruby's strong type system means we're already having to
concern ourselves with passing around valid types
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
✨
Ruby 3
• RBS,a language for describing the types of a Ruby program.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
36.
✨
Ruby 3
• RBS,a language for describing the types of a Ruby program.
• Typeprof
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
NoMethodErrors
# Here wetry to call an instance method on the CreditCard class
class CreditCard
def number
end
end
CreditCard.number
NoMethodError (undefined method `number' for CreditCard:Class)
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
40.
Type Signature Support(RBS)
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
41.
Type Signature Support(RBS)
• Separate file of type declarations, similar to .d.ts in Typescript
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
42.
Type Signature Support(RBS)
• Separate file of type declarations, similar to .d.ts in Typescript
• Standalone language, separate from Ruby but describes Ruby
types
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Payments Example
class CreditCard
...
end
classDebitCard
...
end
class User
def payment_method
# (Returns CreditCard or DebitCard)
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
49.
Payments Example
class CreditCard
...
end
classDebitCard
...
end
class User
def payment_method
# (Returns CreditCard or DebitCard or Instalments)
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Payments Example
! !!
ArgumentError: "unknown payment type"
! ! !
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
52.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
else
raise 'unknown payment type'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
53.
Payments Example
# sig/user.rbs
classUser
def payment_method: () -> ???
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
54.
Payments Example
class PaymentMethod
defcharge(_amount)
raise 'unimplemented'
end
end
interface _PaymentMethod
def charge: (Money amount) -> void
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
55.
Payments Example
class PaymentMethod
defcharge(_amount)
raise 'unimplemented'
end
end
interface _PaymentMethod
def charge: (Money amount) -> void
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
56.
Payments Example
interface _PaymentMethod
defcharge: (Money amount) -> void
end
class DebitCard
include _PaymentMethod # Note: not actually adding any behaviour!
def charge
...
end
end
class CreditCard
include _PaymentMethod # Note: not actually adding any behaviour!
def charge
...
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
57.
Payments Example
# sig/user.rbs
classUser
def payment_method: () -> _PaymentMethod
end
# sig/payment_method_presenter.rbs
class PaymentMethodPresenter
attr_reader payment_method: _PaymentMethod
def render: () -> String
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
58.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when creditcard
render snippet: 'credit_card'
when debitcard
render snippet: 'debit_card'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
61.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
62.
Payments Example
!
We canuse a union type definition to specify permitted types.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
63.
Payments Example
# sig/user.rbs
typepayment_method = DebitCard | CreditCard
class User
def payment_method: () -> payment_method
end
# sig/payment_method_presenter.rbs
class PaymentMethodPresenter
attr_reader payment_method: payment_method
def render: () -> String
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
64.
Payments Example
# sig/user.rbs
typepayment_method = DebitCard | CreditCard | Instalments
class User
def payment_method: () -> payment_method
end
# sig/payment_method_presenter.rbs
class PaymentMethodPresenter
attr_reader payment_method: payment_method
def render: () -> String
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
65.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
66.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
67.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
when Instalments
render snippet: 'instalments'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
68.
Payments Example
class PaymentMethodPresenter
defrender
case payment_method
when CreditCard
render snippet: 'credit_card'
when DebitCard
render snippet: 'debit_card'
when Instalments
render snippet: 'instalments'
end
end
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
69.
Payments Example
# sig/user.rbs
typepayment_method = DebitCard | CreditCard | Instalments
class User
def payment_method: () -> payment_method
end
# sig/payment_method_presenter.rbs
class PaymentMethodPresenter
attr_reader payment_method: payment_method
def render: () -> String
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
70.
What about reducingNoMethodError?
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Addressable Example
version =Addressable::URI.parse(url).query_values['v']
unless version
render :bad_request
return
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Addressable Example
class Baddressable
definitialize(uri)
@uri = uri
end
def query_values
Hash[*URI.parse(@uri).query.split("=")]
end
end
Baddressable.new("https://example.com").query_values['v']
baddressable.rbs:
class Baddressable
def initialize: (String?) -> void
def query_values: -> Hash[String, String]?
end
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
75.
Addressable Example
[error] Type`(::Hash[::String, ::String] | nil)` does not have method `[]`
│ Diagnostic ID: Ruby::NoMethod
│
└ Baddressable.new("https://example.com").query_values['v']
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
Takeaways
• Types werealways there; now we're able to work with them
more intentionally in Ruby.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
78.
Takeaways
• Types werealways there; now we're able to work with them
more intentionally in Ruby.
• Using these type checking tools can help us ensure errors really
only happen once by making our code a little smarter.
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
79.
Takeaways
• Types werealways there; now we're able to work with them
more intentionally in Ruby.
• Using these type checking tools can help us ensure errors really
only happen once by making our code a little smarter.
• It's going to take adoption and use by the community for this
feature to be as successful as possible!
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
80.
Thank you!
Sam Doiron@conlectus
Fleur de Ruby meetup @fleur_de_ruby
Grusp for hosting this event, & you for attending!
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/
81.
Go forth &build with types!
@thecodewitch, slides available at thecodewitch.codes/checking-your-types/