Slide 1

Slide 1 text

Coercion in Ruby Between the strong and weak typing

Slide 2

Slide 2 text

Grzegorz Witek

Slide 3

Slide 3 text

Strong vs. weak typing $> 3 + “a” Python: unsupported operand type(s) for +: 'int' and 'str' Ruby: String can't be coerced into Fixnum Javascript: “3a”

Slide 4

Slide 4 text

Strong vs. weak typing $> 3 + “a” Python: unsupported operand type(s) for +: 'int' and 'str' Ruby: String can't be coerced into Fixnum Javascript: “3a”

Slide 5

Slide 5 text

Coercion in Ruby class Money < Struct.new(:amount) def *(value)
 amount * value
 end end

Slide 6

Slide 6 text

How do I Ruby? money = Money.new(3) money * 2 # => 6 2 * money # => ERROR U FAIL

Slide 7

Slide 7 text

Bad solution class Fixnum
 alias :old_multiply :* def *(val)
 if defined?(Money) && val.is_a?(Money)
 return self * val.amount
 else
 old_multiply(val)
 end
 end
 end

Slide 8

Slide 8 text

Bad solution Pros: works Cons: it’s wrong on as many levels as you can imagine


Slide 9

Slide 9 text

Good solution class Money < Struct.new(:amount)
 
 def *(value)
 amount * value
 end def coerce(other) 
 [self, other]
 end end

Slide 10

Slide 10 text

Good solution def coerce(other) 
 [self, other]
 end

Slide 11

Slide 11 text

Good solution def coerce(other) 
 [other, amount]
 end

Slide 12

Slide 12 text

How does it work? Short answer: when Ruby can’t handle the param type, it calls arg.coerce(self) it gets 2 elements array, and calls array[0].method(array[1])

Slide 13

Slide 13 text

How does it work? Fixnum#*(Money) => omg, what to do?

Slide 14

Slide 14 text

How does it work? Fixnum#(Money)* => omg, what to do? Money#coerce => [Money, Fixnum]

Slide 15

Slide 15 text

How does it work? Fixnum#*(Money) => omg, what to do? Money#coerce => [Money, Fixnum] Money#*(Fixnum) => I know how to handle it!

Slide 16

Slide 16 text

Coercion in Ruby Thanks! Grzegorz Witek
 @arnvald