Threequals - Case Equality in Ruby

Post on 14-Jun-2015

167 views 0 download

Tags:

description

There are many things that make Ruby a great language, but above all else, the beautiful and friendly syntax. A perfect exemplar of this is the case statement: case enables a flexible method of dispatching on an object that is both natural and intuitive. But case can't do it alone. No, it requires the help of it's little-known and under-appreciated sidekick the === (threequals) operator. In this talk we'll dive into this fascinating corner of the Ruby language and see what trouble we can cause with the humble threequals. We'll go over the basics of how it interacts with case, and then go into some tips and tricks for making the most of this useful bit of syntax, and ultimately create a little pattern matching mini-language as a demonstration.

Transcript of Threequals - Case Equality in Ruby

Threequals

Ruby's greatest operator===

Me

===

/Lou(?: Scoras)/ === nameemail === "lou@econify.com"codes === :"github.com/ljsc"

10..(1.0/0) === ruby.years_codingworks === "Econify.com"

Me

The equals sign

===

What does it mean in ruby?

The equals sign

It depends on how

The equals sign

loudly youYELL.

=(Whispered.)

==(Inside voice.)

===(IRC SHOUT!)

Case Equality

===

Case Equality

Use case equality whenever you need to discriminate between one or more cases.

Case Equality

This operator and the case statement go hand in hand.

Case Equality

x = gets.strip.to_i

case xwhen 1 then "one"when 2 then "two"when 3 then "three"end

Case Equality

x = gets.strip.to_i

case xwhen 1 then "one"when 2 then "two"when 3 then "three"end

if 1 === x "one"elsif 2 === x "two"elsif 3 === x "three"end

Case Equality

case x when 1 then "one"

if 1 === x

Case Equality

Case equality is not symmetric in general.

Case Equality

pattern target===

Case Equality

if 1 === x "easy"elsif 2 === x || 3 === x "struggling"else "Why do you make me work so hard?"end

case xwhen 1 then "easy"when 2, 3 "struggling"else "Why do you make me work so hard?"end

The Default

===

The Default

"For class Object, effectively the same as calling ==, but typically overridden by descendants to provide meaningful semantics in case statements."

Useful Builtins

===

Useful Builtins

Class Semantics Notes

Object ==

Regex match Returns a boolean

Range include?

Fixnum/Bignum/Float == Coerces numeric types

Class (Module) is_a? On an instance

Proc call

Predicate Objects

===

Predicate Objects

Predicates are functions that return a boolean value.

Predicate Objects

Create objects to encapsulate case equality operations.

Predicate Objects

What is your quest?

Predicate Objects

class Proceed def ===(knight) knight.favorite_color == "blue" endend

Predicate Objects

class Doomed def ===(knight) knight.knows_capital?("Assyria") endend

Predicate Objects

def cross_bridge!(knight) case knight when Doomed.new then "ARGGGH!!" when Proceed.new then "Right, off you go" endend

Parameterize!

===

Parameterize!

class LikesColor def initialize(color) @color = color end def ===(knight) knight.favorite_color == @color endend

Parameterize!

def cross_bridge!(knight) case knight when LikesColor.new("Yellow") "ARGGGH!!" when LikesColor.new("Blue") "Right, off you go" endend

Composites

===

Composite Pattern

"The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object."

http://en.wikipedia.org/wiki/Composite_pattern

Composite Pattern

UML (purposefully) omitted.

Composite Pattern

Composite Pattern

The "has-a" is not the important part!

Composite Pattern

The "has-a" is not the important part!

Not limited to things that are obviously trees.

Composite Pattern

The most important idea in programming (™): Closure

Composite Pattern

(Not the lexical kind)

The most important idea in programming (™): Closure

Closure Property

Closed operation: Takes one or more object of type T and returns something of type T.

f : Tn -> T

The BridgePt.2

===

The Bridge pt.2

class Or def initialize(a, b) @a, @b = a, b end def ===(other) @a === other || @b === other endend

The Bridge pt.2

class Or def initialize(a, b) @a, @b = a, b end def ===(other) @a === other || @b === other endend

The magic part

The Bridge Pt.2

def cross_bridge!(knight) case knight when Or.new(KnightNamed.new("Lancelot"), KnightNamed.new("Arthur") "Right, off you go" when WearingColor.new("Green") "Kind of arbitrary isn....ARGGGH!!" endend

What a Mouthful

===

What a Mouthful

What a Mouthful

This is all very nice, but it's kind of verbose.

What a Mouthful

This might be a good time for a very thin "DSL" layer.

What a Mouthful

module Threequals::DSL def _and(a,b); And.new(a,b) end def _or(a,b); Or.new(a,b) end def named(a); KnightNamed.new(a) end def doomed(a); Doomed.new(a) endend

The Bridge Pt.3

===

The Bridge Pt.3

def cross_bridge!(knight) extend Threequals::DSL case knight when _or(named("Lancelot"), named("Arthur")) "Right, off you go" when wears "Green" "Kind of arbitrary isn....ARGGGH!!" endend

On Duck Typing

===

On Duck Typing

Why does this work so well for ===?

On Duck Typing

Duck types work best when:

On Duck Typing

Duck types work best when:● The operation(s) are abstract.

On Duck Typing

Duck types work best when:● The operation(s) are abstract.● The interface is granular.

On Duck Typing

Ruby should code should steal this part of functional programming.

On Duck Typing

Ruby should code should steal this part of functional programming.

Not "Proc Soup".

Wrapping Up

===

Wrapping up

We should steal functional ideas, but make them idiomatic

Wrapping up

We should steal functional ideas, but make them idiomatic (we created a poormans pattern matching).

Wrapping up

We should steal functional ideas, but make them idiomatic (we created a poormans pattern matching).

Threequals/case is awesome. Use it.

Wrapping up

We should steal functional ideas, but make them idiomatic (we created a poormans pattern matching).

Threequals/case is awesome. Use it.

Composition is king!

Thanks!

===

Questions?

===

Image credits

"Loud" John Watson. https://flic.kr/p/UfVK"Bridge Climb" Alan. https://flic.kr/p/acyZPw"Compound of five small stellated dodecahedra"

fdecomite. https://flic.kr/p/9ZfhWf"peekaboo" ankakay. https://flic.kr/p/6TSAPW