SlideShare a Scribd company logo
puts 'Hello, Minsk.rb !'
I18n.locale = :ru
puts I18n.t('me.first_name')
#=> Женя
my_contact = Contact.mine
puts my_contact.company
#=> iTechArt
The dark side of Ruby, or Learn functional programming with Ruby
The dark side of Ruby, or Learn functional programming with Ruby
The dark side of Ruby, or Learn functional programming with Ruby
The dark side of Ruby, or Learn functional programming with Ruby
The dark side of Ruby
Learn functional
programming
with Ruby
Learn functional
programming...
with Ruby !
Why functional
programming? !
It's all about hype !
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 12/178
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 13/178
Moore’s law
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 14/178
Moore’s law
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 15/178
Moore’s law
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 16/178
RAM price
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 17/178
RAM price
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 18/178
Let's ask Uncle Bob
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 19/178
Why functional programming?
FP is easier to write, easier to read, easier to test, and easier to
understand.
— Robert C. Martin (Uncle Bob)
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 20/178
Why me?
I'm not a guru
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 22/178
Why Ruby?
What do we know
about Ruby?
Almost Everything is an object
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 25/178
Ruby is thoroughly object-oriented
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 26/178
Ruby is thoroughly object-oriented
1.class #=> Integer
3.14.class #=> Float
'string'.class #=> String
[1, 'string'].class #=> Array
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 27/178
Ruby is thoroughly object-oriented
MyArray = Class.new(Array) do
def append(new_item)
self << new_item
end
def prepend(new_item)
unshift(new_item)
end
end
MyArray.class #=> Class
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 28/178
Ruby is thoroughly object-oriented
my_array = MyArray[1, 2, 3]
append_method = my_array.method(:append)
append_method.class #=> Method
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 29/178
Ruby is multi-paradigm
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 30/178
Ruby is multi-paradigm
Ruby has been described as a multi-paradigm programming language:
it allows procedural programming (defining functions/variables
outside classes makes them part of the root, 'self' Object), with object
orientation (everything is an object) or functional programming (it has
anonymous functions, closures, and continuations; statements all have
values, and functions return the last evaluation)
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 31/178
Let's ask Matz
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 32/178
Matz about Ruby
Ruby is a language designed in the following steps:
* take a simple lisp language (like one prior to CL).
* remove macros, s-expression.
* add simple object system (much simpler than CLOS).
* add blocks, inspired by higher order functions.
* add methods found in Smalltalk.
* add functionality found in Perl (in OO way).
So, Ruby was a Lisp originally, in theory.
Let's call it MatzLisp from now on. ;-)
— matz
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 33/178
class Ruby
# ...
include Lisp
include Perl
include Smalltalk
# ...
end
MatzLisp = Ruby
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 34/178
Smalltalk
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 35/178
Perl
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 36/178
Lisp
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 37/178
Lisp
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 38/178
Scheme
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 39/178
Clojure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 40/178
Bubble-sort in Clojure
(defn- bubble [ys x]
(if-let [y (peek ys)]
(if (> y x)
(conj (pop ys) x y)
(conj ys x))
[x]))
(defn bubble-sort [xs]
(let [ys (reduce bubble [] xs)]
(if (= xs ys)
xs
(recur ys))))
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 41/178
Ruby allows functional
programming
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 42/178
What is functional
programming?
What is functional programming?
Functional programming is a programming paradigm that treats
computation as the evaluation of mathematical functions and avoids
changing-state and mutable data.
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 44/178
It's all about functions
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 45/178
What is function?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 46/178
What is function?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 47/178
Learn FP concepts
with Ruby
FP concepts
» First-class function
» Higher-order functions
» Pure functions
» Currying
» Lazy evaluation
» Immutable data
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 49/178
First-class function
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 50/178
First-class function
» Assigning functions to variables
» Returning functions as the values from other functions
» Passing functions as arguments
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 51/178
First-class function
add = ->(x, y) { x + y }
add.call(2, 2)
#=> 4
multiply = proc { |x, y| x * y }
multiply.call(3, 3)
#=> 9
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 52/178
First-class function
add = ->(x, y) { x + y }
add.call(2, 2)
#=> 4
multiply = proc { |x, y| x * y }
multiply.call(3, 3)
#=> 9
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 53/178
First-class function
add = ->(x, y) { x + y }
add.call(2, 2)
#=> 4
multiply = proc { |x, y| x * y }
multiply.call(3, 3)
#=> 9
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 54/178
First-class function
build_add_function = proc do |x|
->(y) { x + y }
end
add_one = build_add_function.call(1)
add_one.call(1)
#=> 2
add_two = build_add_function.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 55/178
First-class function
build_add_function = proc do |x|
->(y) { x + y }
end
add_one = build_add_function.call(1)
add_one.call(1)
#=> 2
add_two = build_add_function.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 56/178
First-class function
build_add_function = proc do |x|
->(y) { x + y }
end
add_one = build_add_function.call(1)
add_one.call(1)
#=> 2
add_two = build_add_function.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 57/178
First-class function
build_add_function = proc do |x|
->(y) { x + y }
end
add_one = build_add_function.call(1)
add_one.call(1)
#=> 2
add_two = build_add_function.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 58/178
f(x) in FP == object in OOP
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 59/178
First-class function
» Assigning functions to variables
» Returning functions as the values from other functions
» Passing functions as arguments
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 60/178
First-class function
» Assigning functions to variables
» Returning functions as the values from other functions
» Passing functions as arguments
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 61/178
Higher-order functions
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 62/178
Higher-order functions
» Takes functions as arguments
» Returns function as a result
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 63/178
Higher-order function that returns
function as a result
build_add_function = proc do |x|
->(y) { x + y }
end
add_one = build_add_function.call(1)
add_one.call(1)
#=> 2
add_two = build_add_function.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 64/178
Higher-order function that takes function
as argument
[1, 2, 3, 4, 5].map { |x| x + 1 }
#=> [2, 3, 4, 5, 6]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 65/178
Higher-order function that takes function
as argument
add_one = ->(x) { x + 1 }
[1, 2, 3, 4, 5].map(&add_one)
#=> => [2, 3, 4, 5, 6]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 66/178
Higher-order function that takes function
as argument
add_one = 1.method(:+)
[1, 2, 3, 4, 5].map(&add_one)
#=> => [2, 3, 4, 5, 6]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 67/178
Higher-order functions
» Takes functions as arguments
» Returns function as a result
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 68/178
Higher-order functions
provide a way to build
useful functions with simple
interface
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 69/178
Pure functions
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 70/178
Pure functions
» Always evaluates the same result value given the same
argument values
» Does not cause any side effect
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 71/178
Pure function
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 72/178
No side effects
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 73/178
No side effects
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 74/178
Pure
add = ->(x, y) { x + y }
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 75/178
Not pure
display = ->(value) { puts value }
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 76/178
Pure
'string'.upcase
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 77/178
Not pure
Time.now
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 78/178
Pure or not?
[1, 2, 3].size
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 79/178
Pure or not?
[1, 2, 3].size
✅ Pure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 80/178
Pure or not?
File.read('/path/to/file')
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 81/178
Pure or not?
File.read('/path/to/file')
❌ Not pure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 82/178
Pure or not?
Random.rand(100_000)
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 83/178
Pure or not?
Random.rand(100_000)
❌ Not pure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 84/178
Pure or not?
map = proc do |collection, function|
array = []
collection.each { |item| array << function.call(item) }
array
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 85/178
Pure or not?
map = proc do |collection, function|
array = []
collection.each { |item| array << function.call(item) }
array
end
✅ Pure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 86/178
Why it is important?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 87/178
Non-pure functions are
unpredictable
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 88/178
Pure functions are
easier to reason about
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 89/178
Which kind of functions
would you like to see more
in your apps?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 90/178
Currying
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 91/178
Currying
Currying is the technique of translating the evaluation of a function
that takes multiple arguments (or a tuple of arguments) into
evaluating a sequence of functions, each with a single argument.
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 92/178
Currying
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 93/178
Currying
add = ->(x, y) { x + y }
add.call(1, 2)
#=> 3
add_one = ->(x) { add.call(1, x) }
add_one.call(2)
#=> 3
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 94/178
Currying
add = ->(x, y) { x + y }
add.call(1, 2)
#=> 3
add_one = ->(x) { add.call(1, x) }
add_one.call(2)
#=> 3
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 95/178
Proc#curry
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 96/178
Proc#curry
add = ->(x, y) { x + y }.curry
add.call(1, 2)
#=> 3
add_one = add.call(1)
add_one.call(1)
#=> 2
add_two = add.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 97/178
Proc#curry
add = ->(x, y) { x + y }.curry
add.call(1, 2)
#=> 3
add_one = add.call(1)
add_one.call(1)
#=> 2
add_two = add.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 98/178
Proc#curry
add = ->(x, y) { x + y }.curry
add.call(1, 2)
#=> 3
add_one = add.call(1)
add_one.call(1)
#=> 2
add_two = add.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 99/178
Proc#curry
add = ->(x, y) { x + y }.curry
add.call(1, 2)
#=> 3
add_one = add.call(1)
add_one.call(1)
#=> 2
add_two = add.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 100/178
Proc#curry
add = ->(x, y) { x + y }.curry
add.call(1, 2)
#=> 3
add_one = add.call(1)
add_one.call(1)
#=> 2
add_two = add.call(2)
add_two.call(2)
#=> 4
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 101/178
Currying allows us to have
small and reusable functions
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 102/178
Lazy evaluation
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 103/178
Lazy evaluation
Lazy evaluation is an evaluation strategy which delays the evaluation
of an expression until its value is needed (non-strict evaluation) and
which also avoids repeated evaluations (sharing).
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 104/178
Eager evaluation
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 105/178
Eager evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3].map(&add_one).map(&times_two)
#=> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 106/178
Eager evaluation
[1, 2, 3] -> map(&add_one) -> [2, 3, 4]
[2, 3, 4] -> map(&times_two) -> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 107/178
Eager evaluation
[1, 2, 3] -> map(&add_one) -> [2, 3, 4]
[2, 3, 4] -> map(&times_two) -> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 108/178
Eager evaluation
[1, 2, 3] -> map(&add_one) -> [2, 3, 4]
[2, 3, 4] -> map(&times_two) -> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 109/178
Lazy evaluation
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 110/178
Enumerator::Lazy in Ruby 2.0
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 111/178
Lazy evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3].map(&add_one).map(&times_two)
#=> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 112/178
Lazy evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3]
.lazy
.map(&add_one)
.map(&times_two)
#=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>:map>
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 113/178
Lazy evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3]
.lazy
.map(&add_one)
.map(&times_two)
#=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>:map>
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 114/178
Lazy evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3]
.lazy
.map(&add_one)
.map(&times_two)
.force
#=> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 115/178
Lazy evaluation
add_one = ->(x) { x + 1 }
times_two = ->(x) { x * 2 }
[1, 2, 3]
.lazy
.map(&add_one)
.map(&times_two)
.force
#=> [4, 6, 8]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 116/178
Lazy evaluation
[1, 2, 3].map do |x|
times_two.call(add_one.call(x))
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 117/178
Lazy evaluation
1 -> add_one -> 2 -> times_two -> 4
2 -> add_one -> 3 -> times_two -> 6
3 -> add_one -> 4 -> times_two -> 8
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 118/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 119/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 120/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 121/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 122/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 123/178
Lazy evaluation
class GenerateRandomString
def call
(0..Float::INFINITY)
.lazy
.map(&method(:generete_random_string))
.select(&method(:genereted_string_is_not_obscene?))
.find(&method(:unique_string?))
end
# ...
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 124/178
Ruby 2.0 Works Hard So You Can Be Lazy, by Pat Shaughnessy
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 125/178
Lazy evaluation allows us
to consume data on demand,
instead of evaluating everything
up front
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 126/178
Immutable data
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 127/178
Immutable data
Immutable object (unchangeable object) is an object whose state
cannot be modified after it is created. This is in contrast to a mutable
object (changeable object), which can be modified after it is created.
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 128/178
Why you should avoid mutation?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 129/178
Why you should avoid mutation?
» Mutation is a source of bugs
» Mutation requires you to spend extra energy when reading and
writing code
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 130/178
Why you should avoid mutation?
string = 'hello'
do_something_with_string(string)
puts string
#=> ???
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 131/178
Why you should avoid mutation?
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 132/178
Ruby allows to mutate data
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 133/178
Ruby allows to mutate data
string = 'hello'
string.upcase!
puts string
#=> "HELLO"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 134/178
Ruby allows to mutate data
array = [1, 2, 3]
array << 4
puts array.inspect
#=> [1, 2, 3, 4]
array.unshift(0)
puts array.inspect
#=> [0, 1, 2, 3, 4]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 135/178
Ruby allows to mutate data
hash = { a: 1, b: 2, c: 3 }
hash.merge!(d: 4)
puts hash
#=> {:a=>1, :b=>2, :c=>3, :d=>4}
hash[:e] = 5
puts hash
#=> {:a=>1, :b=>2, :c=>3, :d=>4, :e=>5}
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 136/178
Immutability In Ruby
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 137/178
Object#freeze
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 138/178
Object#freeze
Point = Struct.new(:x, :y)
zero_point = Point.new(0, 0)
zero_point.freeze
zero_point.x = 1 #=> RuntimeError: can't modify frozen Point
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 139/178
Object#freeze
Point = Struct.new(:x, :y)
zero_point = Point.new(0, 0)
zero_point.freeze
zero_point.x = 1 #=> RuntimeError: can't modify frozen Point
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 140/178
Object#freeze
languages = ['Ruby', 'Elixir'].freeze
languages << 'Go' #=> RuntimeError: can't modify frozen Array
languages[0].upcase!
p languages
#=> ["RUBY", "Elixir"]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 141/178
Object#freeze
languages = ['Ruby', 'Elixir'].freeze
languages << 'Go' #=> RuntimeError: can't modify frozen Array
languages[0].upcase!
p languages
#=> ["RUBY", "Elixir"]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 142/178
Object#freeze
languages = ['Ruby', 'Elixir'].freeze
languages << 'Go' #=> RuntimeError: can't modify frozen Array
languages[0].upcase!
p languages
#=> ["RUBY", "Elixir"]
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 143/178
Frozen string literals in Ruby 2.3
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 144/178
Frozen string literals in Ruby 2.3
string = 'hello'
string.upcase!
puts string
#=> HELLO
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 145/178
Frozen string literals in Ruby 2.3
# frozen_string_literal: true
string = 'hello'
string.upcase! #=> RuntimeError: can't modify frozen String
puts string
#=> hello
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 146/178
Frozen string literals in Ruby 2.3
# frozen_string_literal: true
string = String.new('hello')
string.upcase!
puts string #=> 'HELLO'
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 147/178
Frozen string literals in Ruby 2.3
# frozen_string_literal: true
string = 'hello'.dup
string.upcase!
puts string #=> 'HELLO'
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 148/178
Design classes to be immutable
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 149/178
Design classes to be immutable
class BlogPost
attr_reader :title, :body
def initialize(title:, body:)
@title = title
@body = body
end
def rename(new_title)
BlogPost.new(title: new_title, body: body)
end
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 150/178
Design classes to be immutable
class BlogPost
attr_reader :title, :body
def initialize(title:, body:)
@title = title
@body = body
end
def rename(new_title)
BlogPost.new(title: new_title, body: body)
end
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 151/178
Design classes to be immutable
class BlogPost
attr_reader :title, :body
def initialize(title:, body:)
@title = title
@body = body
end
def rename(new_title)
BlogPost.new(title: new_title, body: body)
end
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 152/178
Design classes to be immutable
post = BlogPost.new(title: 'Hi', body: 'This is my first post')
#=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post">
renamed_post = post.rename('First Post')
#=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post">
post.title
#=> "Hi"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 153/178
Design classes to be immutable
post = BlogPost.new(title: 'Hi', body: 'This is my first post')
#=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post">
renamed_post = post.rename('First Post')
#=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post">
post.title
#=> "Hi"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 154/178
Design classes to be immutable
post = BlogPost.new(title: 'Hi', body: 'This is my first post')
#=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post">
renamed_post = post.rename('First Post')
#=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post">
post.title
#=> "Hi"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 155/178
Persistent data structures
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 156/178
Persistent data structures
Persistent data structure is a data structure that always preserves the
previous version of itself when it is modified. Such data structures are
effectively immutable, as their operations do not (visibly) update the
structure in-place, but instead always yield a new updated structure.
— Wikipedia
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 157/178
Hamster gem
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 158/178
Hamster gem
Efficient, immutable, and thread-safe collection classes for Ruby.
Hamster provides 6 Persistent Data Structures: Hash, Vector, Set,
SortedSet, List, and Deque (which works as an immutable queue or
stack).
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 159/178
Hamster::Hash
require 'hamster/hash'
john = Hamster::Hash[name: 'John', gender: :male]
#=> Hamster::Hash[:name => "John", :gender => :male]
john[:name]
#=> "John"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 160/178
Hamster::Hash
require 'hamster/hash'
peter = john.put(:name, 'Peter')
#=> Hamster::Hash[:name => "Peter", :gender => :male]
peter[:name]
#=> "Peter"
john[:name]
#=> "John"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 161/178
Hamster::Hash
require 'hamster/hash'
male = john.delete(:name)
#=> Hamster::Hash[:gender => :male]
male[:name]
#=> nil
john[:name]
#=> "John"
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 162/178
Why you should avoid mutation?
» Mutation is a source of bugs
» Mutation requires you to spend extra energy when reading and
writing code
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 163/178
Ruby has many
functional features !
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 164/178
Ruby allows you
to blend functional and OO
approaches
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 165/178
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 166/178
...but Ruby
is not a functional language !
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 167/178
Try to learn functional language
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 168/178
Scala
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 169/178
Clojure
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 170/178
Haskell
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 171/178
Elm
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 172/178
Erlang
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 173/178
Elixir
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 174/178
Elixir
defmodule Quicksort do
def sort(list) when length(list) <= 1, do: list
def sort(list) do
[pivot | rest] = list
{before_pivot, after_pivot} = split_relative_to_pivot(pivot, rest)
merge_parts(pivot, sort(before_pivot), sort(after_pivot))
end
defp split_relative_to_pivot(pivot, list) do
Enum.split_with(list, fn(x) -> x < pivot end)
end
defp merge_parts(pivot, before_pivot, after_pivot) do
before_pivot ++ [pivot | after_pivot]
end
end
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 175/178
Thank you! !
Questions? !
Happy hacking! !
The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 178/178

More Related Content

What's hot (20)

Python Programming | JNTUA | UNIT 2 | Case Study |
Python Programming | JNTUA | UNIT 2 | Case Study | Python Programming | JNTUA | UNIT 2 | Case Study |
Python Programming | JNTUA | UNIT 2 | Case Study |
FabMinds
 
Greach 2014 - Metaprogramming with groovy
Greach 2014 - Metaprogramming with groovyGreach 2014 - Metaprogramming with groovy
Greach 2014 - Metaprogramming with groovy
Iván López Martín
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
Garth Gilmour
 
Ebay News 2001 4 19 Earnings
Ebay News 2001 4 19 EarningsEbay News 2001 4 19 Earnings
Ebay News 2001 4 19 Earnings
QuarterlyEarningsReports
 
P4 P Update January 2009
P4 P Update January 2009P4 P Update January 2009
P4 P Update January 2009
vsainteluce
 
Ebay News 2000 10 19 Earnings
Ebay News 2000 10 19 EarningsEbay News 2000 10 19 Earnings
Ebay News 2000 10 19 Earnings
QuarterlyEarningsReports
 
What's New in Groovy 1.6?
What's New in Groovy 1.6?What's New in Groovy 1.6?
What's New in Groovy 1.6?
Guillaume Laforge
 
Intro to Functional Programming
Intro to Functional ProgrammingIntro to Functional Programming
Intro to Functional Programming
Jordan Parmer
 
Communication between Java and Python
Communication between Java and PythonCommunication between Java and Python
Communication between Java and Python
Andreas Schreiber
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in Code
Eamonn Boyle
 
Pré Descobrimento Do Brasil
Pré Descobrimento Do BrasilPré Descobrimento Do Brasil
Pré Descobrimento Do Brasil
ecsette
 
Thinking in Functions
Thinking in FunctionsThinking in Functions
Thinking in Functions
Alexandru Bolboaca
 
Jython: Integrating Python and Java
Jython: Integrating Python and JavaJython: Integrating Python and Java
Jython: Integrating Python and Java
Charles Anderson
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
kim.mens
 
Parallel Programming
Parallel ProgrammingParallel Programming
Parallel Programming
Roman Okolovich
 
Ruby Presentation
Ruby Presentation Ruby Presentation
Ruby Presentation
platico_dev
 
Introduction to MPI
Introduction to MPIIntroduction to MPI
Introduction to MPI
Akhila Prabhakaran
 
Introduction to functional programming
Introduction to functional programmingIntroduction to functional programming
Introduction to functional programming
Konrad Szydlo
 
What do you mean it needs to be Java based? How jython saved the day.
What do you mean it needs to be Java based? How jython saved the day.What do you mean it needs to be Java based? How jython saved the day.
What do you mean it needs to be Java based? How jython saved the day.
Mark Rees
 
Introduction to OpenMP
Introduction to OpenMPIntroduction to OpenMP
Introduction to OpenMP
Akhila Prabhakaran
 
Python Programming | JNTUA | UNIT 2 | Case Study |
Python Programming | JNTUA | UNIT 2 | Case Study | Python Programming | JNTUA | UNIT 2 | Case Study |
Python Programming | JNTUA | UNIT 2 | Case Study |
FabMinds
 
Greach 2014 - Metaprogramming with groovy
Greach 2014 - Metaprogramming with groovyGreach 2014 - Metaprogramming with groovy
Greach 2014 - Metaprogramming with groovy
Iván López Martín
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
Garth Gilmour
 
P4 P Update January 2009
P4 P Update January 2009P4 P Update January 2009
P4 P Update January 2009
vsainteluce
 
Intro to Functional Programming
Intro to Functional ProgrammingIntro to Functional Programming
Intro to Functional Programming
Jordan Parmer
 
Communication between Java and Python
Communication between Java and PythonCommunication between Java and Python
Communication between Java and Python
Andreas Schreiber
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in Code
Eamonn Boyle
 
Pré Descobrimento Do Brasil
Pré Descobrimento Do BrasilPré Descobrimento Do Brasil
Pré Descobrimento Do Brasil
ecsette
 
Jython: Integrating Python and Java
Jython: Integrating Python and JavaJython: Integrating Python and Java
Jython: Integrating Python and Java
Charles Anderson
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
kim.mens
 
Ruby Presentation
Ruby Presentation Ruby Presentation
Ruby Presentation
platico_dev
 
Introduction to functional programming
Introduction to functional programmingIntroduction to functional programming
Introduction to functional programming
Konrad Szydlo
 
What do you mean it needs to be Java based? How jython saved the day.
What do you mean it needs to be Java based? How jython saved the day.What do you mean it needs to be Java based? How jython saved the day.
What do you mean it needs to be Java based? How jython saved the day.
Mark Rees
 

Similar to The dark side of Ruby, or Learn functional programming with Ruby (20)

Ruby Functional Programming
Ruby Functional ProgrammingRuby Functional Programming
Ruby Functional Programming
Geison Goes
 
Functional programming and ruby in functional style
Functional programming and ruby in functional styleFunctional programming and ruby in functional style
Functional programming and ruby in functional style
Niranjan Sarade
 
Funtional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail BortnykFuntional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail Bortnyk
Ruby Meditation
 
Functional Ruby
Functional RubyFunctional Ruby
Functional Ruby
Amoniac OÜ
 
Ruby Programming
Ruby ProgrammingRuby Programming
Ruby Programming
Sadakathullah Appa College
 
Ruby training day1
Ruby training day1Ruby training day1
Ruby training day1
Bindesh Vijayan
 
Ruby Basics
Ruby BasicsRuby Basics
Ruby Basics
NagaLakshmi_N
 
DZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20RubyDZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20Ruby
tutorialsruby
 
DZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20RubyDZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20Ruby
tutorialsruby
 
IJTC%202009%20JRuby
IJTC%202009%20JRubyIJTC%202009%20JRuby
IJTC%202009%20JRuby
tutorialsruby
 
IJTC%202009%20JRuby
IJTC%202009%20JRubyIJTC%202009%20JRuby
IJTC%202009%20JRuby
tutorialsruby
 
Ruby an overall approach
Ruby an overall approachRuby an overall approach
Ruby an overall approach
Felipe Schmitt
 
Functional programming in ruby
Functional programming in rubyFunctional programming in ruby
Functional programming in ruby
Koen Handekyn
 
Workin ontherailsroad
Workin ontherailsroadWorkin ontherailsroad
Workin ontherailsroad
Jim Jones
 
WorkinOnTheRailsRoad
WorkinOnTheRailsRoadWorkinOnTheRailsRoad
WorkinOnTheRailsRoad
webuploader
 
The Well-Grounded Nuby
The Well-Grounded NubyThe Well-Grounded Nuby
The Well-Grounded Nuby
David Black
 
Ruby from zero to hero
Ruby from zero to heroRuby from zero to hero
Ruby from zero to hero
Diego Lemos
 
All I want for Matz-mas
All I want for Matz-masAll I want for Matz-mas
All I want for Matz-mas
Andrew Grimm
 
Ruby for .NET developers
Ruby for .NET developersRuby for .NET developers
Ruby for .NET developers
Max Titov
 
Meta Programming in Ruby - Code Camp 2010
Meta Programming in Ruby - Code Camp 2010Meta Programming in Ruby - Code Camp 2010
Meta Programming in Ruby - Code Camp 2010
ssoroka
 
Ruby Functional Programming
Ruby Functional ProgrammingRuby Functional Programming
Ruby Functional Programming
Geison Goes
 
Functional programming and ruby in functional style
Functional programming and ruby in functional styleFunctional programming and ruby in functional style
Functional programming and ruby in functional style
Niranjan Sarade
 
Funtional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail BortnykFuntional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail Bortnyk
Ruby Meditation
 
DZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20RubyDZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20Ruby
tutorialsruby
 
DZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20RubyDZone%20-%20Essential%20Ruby
DZone%20-%20Essential%20Ruby
tutorialsruby
 
Ruby an overall approach
Ruby an overall approachRuby an overall approach
Ruby an overall approach
Felipe Schmitt
 
Functional programming in ruby
Functional programming in rubyFunctional programming in ruby
Functional programming in ruby
Koen Handekyn
 
Workin ontherailsroad
Workin ontherailsroadWorkin ontherailsroad
Workin ontherailsroad
Jim Jones
 
WorkinOnTheRailsRoad
WorkinOnTheRailsRoadWorkinOnTheRailsRoad
WorkinOnTheRailsRoad
webuploader
 
The Well-Grounded Nuby
The Well-Grounded NubyThe Well-Grounded Nuby
The Well-Grounded Nuby
David Black
 
Ruby from zero to hero
Ruby from zero to heroRuby from zero to hero
Ruby from zero to hero
Diego Lemos
 
All I want for Matz-mas
All I want for Matz-masAll I want for Matz-mas
All I want for Matz-mas
Andrew Grimm
 
Ruby for .NET developers
Ruby for .NET developersRuby for .NET developers
Ruby for .NET developers
Max Titov
 
Meta Programming in Ruby - Code Camp 2010
Meta Programming in Ruby - Code Camp 2010Meta Programming in Ruby - Code Camp 2010
Meta Programming in Ruby - Code Camp 2010
ssoroka
 
Ad

Recently uploaded (20)

Rebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core FoundationRebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core Foundation
Cadabra Studio
 
Automating Map Production With FME and Python
Automating Map Production With FME and PythonAutomating Map Production With FME and Python
Automating Map Production With FME and Python
Safe Software
 
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
SheenBrisals
 
FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025
Safe Software
 
Online Queue Management System for Public Service Offices [Focused on Municip...
Online Queue Management System for Public Service Offices [Focused on Municip...Online Queue Management System for Public Service Offices [Focused on Municip...
Online Queue Management System for Public Service Offices [Focused on Municip...
Rishab Acharya
 
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdfTop 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Trackobit
 
14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework
Angelo Theodorou
 
Best Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small BusinessesBest Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small Businesses
TheTelephony
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - IntroductionIBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdfThe Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
Varsha Nayak
 
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps CyclesFrom Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
Marjukka Niinioja
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native BarcelonaOpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
WSO2
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlowDevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First DevelopmentDesign by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Plooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your wayPlooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your way
Plooma
 
Essentials of Resource Planning in a Downturn
Essentials of Resource Planning in a DownturnEssentials of Resource Planning in a Downturn
Essentials of Resource Planning in a Downturn
OnePlan Solutions
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
Rebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core FoundationRebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core Foundation
Cadabra Studio
 
Automating Map Production With FME and Python
Automating Map Production With FME and PythonAutomating Map Production With FME and Python
Automating Map Production With FME and Python
Safe Software
 
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
SheenBrisals
 
FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025
Safe Software
 
Online Queue Management System for Public Service Offices [Focused on Municip...
Online Queue Management System for Public Service Offices [Focused on Municip...Online Queue Management System for Public Service Offices [Focused on Municip...
Online Queue Management System for Public Service Offices [Focused on Municip...
Rishab Acharya
 
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdfTop 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Trackobit
 
14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework
Angelo Theodorou
 
Best Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small BusinessesBest Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small Businesses
TheTelephony
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - IntroductionIBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdfThe Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
Varsha Nayak
 
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps CyclesFrom Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
From Chaos to Clarity - Designing (AI-Ready) APIs with APIOps Cycles
Marjukka Niinioja
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native BarcelonaOpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
WSO2
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlowDevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First DevelopmentDesign by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Plooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your wayPlooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your way
Plooma
 
Essentials of Resource Planning in a Downturn
Essentials of Resource Planning in a DownturnEssentials of Resource Planning in a Downturn
Essentials of Resource Planning in a Downturn
OnePlan Solutions
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
Ad

The dark side of Ruby, or Learn functional programming with Ruby

  • 2. I18n.locale = :ru puts I18n.t('me.first_name') #=> Женя
  • 3. my_contact = Contact.mine puts my_contact.company #=> iTechArt
  • 8. The dark side of Ruby
  • 12. It's all about hype ! The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 12/178
  • 13. The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 13/178
  • 14. Moore’s law The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 14/178
  • 15. Moore’s law The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 15/178
  • 16. Moore’s law The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 16/178
  • 17. RAM price The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 17/178
  • 18. RAM price The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 18/178
  • 19. Let's ask Uncle Bob The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 19/178
  • 20. Why functional programming? FP is easier to write, easier to read, easier to test, and easier to understand. — Robert C. Martin (Uncle Bob) The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 20/178
  • 22. I'm not a guru The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 22/178
  • 24. What do we know about Ruby?
  • 25. Almost Everything is an object The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 25/178
  • 26. Ruby is thoroughly object-oriented The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 26/178
  • 27. Ruby is thoroughly object-oriented 1.class #=> Integer 3.14.class #=> Float 'string'.class #=> String [1, 'string'].class #=> Array The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 27/178
  • 28. Ruby is thoroughly object-oriented MyArray = Class.new(Array) do def append(new_item) self << new_item end def prepend(new_item) unshift(new_item) end end MyArray.class #=> Class The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 28/178
  • 29. Ruby is thoroughly object-oriented my_array = MyArray[1, 2, 3] append_method = my_array.method(:append) append_method.class #=> Method The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 29/178
  • 30. Ruby is multi-paradigm The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 30/178
  • 31. Ruby is multi-paradigm Ruby has been described as a multi-paradigm programming language: it allows procedural programming (defining functions/variables outside classes makes them part of the root, 'self' Object), with object orientation (everything is an object) or functional programming (it has anonymous functions, closures, and continuations; statements all have values, and functions return the last evaluation) — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 31/178
  • 32. Let's ask Matz The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 32/178
  • 33. Matz about Ruby Ruby is a language designed in the following steps: * take a simple lisp language (like one prior to CL). * remove macros, s-expression. * add simple object system (much simpler than CLOS). * add blocks, inspired by higher order functions. * add methods found in Smalltalk. * add functionality found in Perl (in OO way). So, Ruby was a Lisp originally, in theory. Let's call it MatzLisp from now on. ;-) — matz The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 33/178
  • 34. class Ruby # ... include Lisp include Perl include Smalltalk # ... end MatzLisp = Ruby The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 34/178
  • 35. Smalltalk The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 35/178
  • 36. Perl The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 36/178
  • 37. Lisp The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 37/178
  • 38. Lisp The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 38/178
  • 39. Scheme The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 39/178
  • 40. Clojure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 40/178
  • 41. Bubble-sort in Clojure (defn- bubble [ys x] (if-let [y (peek ys)] (if (> y x) (conj (pop ys) x y) (conj ys x)) [x])) (defn bubble-sort [xs] (let [ys (reduce bubble [] xs)] (if (= xs ys) xs (recur ys)))) The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 41/178
  • 42. Ruby allows functional programming The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 42/178
  • 44. What is functional programming? Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 44/178
  • 45. It's all about functions The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 45/178
  • 46. What is function? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 46/178
  • 47. What is function? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 47/178
  • 49. FP concepts » First-class function » Higher-order functions » Pure functions » Currying » Lazy evaluation » Immutable data The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 49/178
  • 50. First-class function The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 50/178
  • 51. First-class function » Assigning functions to variables » Returning functions as the values from other functions » Passing functions as arguments The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 51/178
  • 52. First-class function add = ->(x, y) { x + y } add.call(2, 2) #=> 4 multiply = proc { |x, y| x * y } multiply.call(3, 3) #=> 9 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 52/178
  • 53. First-class function add = ->(x, y) { x + y } add.call(2, 2) #=> 4 multiply = proc { |x, y| x * y } multiply.call(3, 3) #=> 9 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 53/178
  • 54. First-class function add = ->(x, y) { x + y } add.call(2, 2) #=> 4 multiply = proc { |x, y| x * y } multiply.call(3, 3) #=> 9 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 54/178
  • 55. First-class function build_add_function = proc do |x| ->(y) { x + y } end add_one = build_add_function.call(1) add_one.call(1) #=> 2 add_two = build_add_function.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 55/178
  • 56. First-class function build_add_function = proc do |x| ->(y) { x + y } end add_one = build_add_function.call(1) add_one.call(1) #=> 2 add_two = build_add_function.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 56/178
  • 57. First-class function build_add_function = proc do |x| ->(y) { x + y } end add_one = build_add_function.call(1) add_one.call(1) #=> 2 add_two = build_add_function.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 57/178
  • 58. First-class function build_add_function = proc do |x| ->(y) { x + y } end add_one = build_add_function.call(1) add_one.call(1) #=> 2 add_two = build_add_function.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 58/178
  • 59. f(x) in FP == object in OOP The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 59/178
  • 60. First-class function » Assigning functions to variables » Returning functions as the values from other functions » Passing functions as arguments The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 60/178
  • 61. First-class function » Assigning functions to variables » Returning functions as the values from other functions » Passing functions as arguments The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 61/178
  • 62. Higher-order functions The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 62/178
  • 63. Higher-order functions » Takes functions as arguments » Returns function as a result The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 63/178
  • 64. Higher-order function that returns function as a result build_add_function = proc do |x| ->(y) { x + y } end add_one = build_add_function.call(1) add_one.call(1) #=> 2 add_two = build_add_function.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 64/178
  • 65. Higher-order function that takes function as argument [1, 2, 3, 4, 5].map { |x| x + 1 } #=> [2, 3, 4, 5, 6] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 65/178
  • 66. Higher-order function that takes function as argument add_one = ->(x) { x + 1 } [1, 2, 3, 4, 5].map(&add_one) #=> => [2, 3, 4, 5, 6] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 66/178
  • 67. Higher-order function that takes function as argument add_one = 1.method(:+) [1, 2, 3, 4, 5].map(&add_one) #=> => [2, 3, 4, 5, 6] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 67/178
  • 68. Higher-order functions » Takes functions as arguments » Returns function as a result The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 68/178
  • 69. Higher-order functions provide a way to build useful functions with simple interface The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 69/178
  • 70. Pure functions The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 70/178
  • 71. Pure functions » Always evaluates the same result value given the same argument values » Does not cause any side effect The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 71/178
  • 72. Pure function The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 72/178
  • 73. No side effects The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 73/178
  • 74. No side effects The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 74/178
  • 75. Pure add = ->(x, y) { x + y } The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 75/178
  • 76. Not pure display = ->(value) { puts value } The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 76/178
  • 77. Pure 'string'.upcase The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 77/178
  • 78. Not pure Time.now The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 78/178
  • 79. Pure or not? [1, 2, 3].size The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 79/178
  • 80. Pure or not? [1, 2, 3].size ✅ Pure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 80/178
  • 81. Pure or not? File.read('/path/to/file') The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 81/178
  • 82. Pure or not? File.read('/path/to/file') ❌ Not pure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 82/178
  • 83. Pure or not? Random.rand(100_000) The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 83/178
  • 84. Pure or not? Random.rand(100_000) ❌ Not pure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 84/178
  • 85. Pure or not? map = proc do |collection, function| array = [] collection.each { |item| array << function.call(item) } array end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 85/178
  • 86. Pure or not? map = proc do |collection, function| array = [] collection.each { |item| array << function.call(item) } array end ✅ Pure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 86/178
  • 87. Why it is important? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 87/178
  • 88. Non-pure functions are unpredictable The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 88/178
  • 89. Pure functions are easier to reason about The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 89/178
  • 90. Which kind of functions would you like to see more in your apps? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 90/178
  • 91. Currying The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 91/178
  • 92. Currying Currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 92/178
  • 93. Currying The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 93/178
  • 94. Currying add = ->(x, y) { x + y } add.call(1, 2) #=> 3 add_one = ->(x) { add.call(1, x) } add_one.call(2) #=> 3 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 94/178
  • 95. Currying add = ->(x, y) { x + y } add.call(1, 2) #=> 3 add_one = ->(x) { add.call(1, x) } add_one.call(2) #=> 3 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 95/178
  • 96. Proc#curry The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 96/178
  • 97. Proc#curry add = ->(x, y) { x + y }.curry add.call(1, 2) #=> 3 add_one = add.call(1) add_one.call(1) #=> 2 add_two = add.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 97/178
  • 98. Proc#curry add = ->(x, y) { x + y }.curry add.call(1, 2) #=> 3 add_one = add.call(1) add_one.call(1) #=> 2 add_two = add.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 98/178
  • 99. Proc#curry add = ->(x, y) { x + y }.curry add.call(1, 2) #=> 3 add_one = add.call(1) add_one.call(1) #=> 2 add_two = add.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 99/178
  • 100. Proc#curry add = ->(x, y) { x + y }.curry add.call(1, 2) #=> 3 add_one = add.call(1) add_one.call(1) #=> 2 add_two = add.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 100/178
  • 101. Proc#curry add = ->(x, y) { x + y }.curry add.call(1, 2) #=> 3 add_one = add.call(1) add_one.call(1) #=> 2 add_two = add.call(2) add_two.call(2) #=> 4 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 101/178
  • 102. Currying allows us to have small and reusable functions The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 102/178
  • 103. Lazy evaluation The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 103/178
  • 104. Lazy evaluation Lazy evaluation is an evaluation strategy which delays the evaluation of an expression until its value is needed (non-strict evaluation) and which also avoids repeated evaluations (sharing). — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 104/178
  • 105. Eager evaluation The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 105/178
  • 106. Eager evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3].map(&add_one).map(&times_two) #=> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 106/178
  • 107. Eager evaluation [1, 2, 3] -> map(&add_one) -> [2, 3, 4] [2, 3, 4] -> map(&times_two) -> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 107/178
  • 108. Eager evaluation [1, 2, 3] -> map(&add_one) -> [2, 3, 4] [2, 3, 4] -> map(&times_two) -> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 108/178
  • 109. Eager evaluation [1, 2, 3] -> map(&add_one) -> [2, 3, 4] [2, 3, 4] -> map(&times_two) -> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 109/178
  • 110. Lazy evaluation The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 110/178
  • 111. Enumerator::Lazy in Ruby 2.0 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 111/178
  • 112. Lazy evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3].map(&add_one).map(&times_two) #=> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 112/178
  • 113. Lazy evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3] .lazy .map(&add_one) .map(&times_two) #=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>:map> The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 113/178
  • 114. Lazy evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3] .lazy .map(&add_one) .map(&times_two) #=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>:map> The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 114/178
  • 115. Lazy evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3] .lazy .map(&add_one) .map(&times_two) .force #=> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 115/178
  • 116. Lazy evaluation add_one = ->(x) { x + 1 } times_two = ->(x) { x * 2 } [1, 2, 3] .lazy .map(&add_one) .map(&times_two) .force #=> [4, 6, 8] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 116/178
  • 117. Lazy evaluation [1, 2, 3].map do |x| times_two.call(add_one.call(x)) end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 117/178
  • 118. Lazy evaluation 1 -> add_one -> 2 -> times_two -> 4 2 -> add_one -> 3 -> times_two -> 6 3 -> add_one -> 4 -> times_two -> 8 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 118/178
  • 119. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 119/178
  • 120. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 120/178
  • 121. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 121/178
  • 122. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 122/178
  • 123. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 123/178
  • 124. Lazy evaluation class GenerateRandomString def call (0..Float::INFINITY) .lazy .map(&method(:generete_random_string)) .select(&method(:genereted_string_is_not_obscene?)) .find(&method(:unique_string?)) end # ... end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 124/178
  • 125. Ruby 2.0 Works Hard So You Can Be Lazy, by Pat Shaughnessy The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 125/178
  • 126. Lazy evaluation allows us to consume data on demand, instead of evaluating everything up front The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 126/178
  • 127. Immutable data The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 127/178
  • 128. Immutable data Immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created. — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 128/178
  • 129. Why you should avoid mutation? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 129/178
  • 130. Why you should avoid mutation? » Mutation is a source of bugs » Mutation requires you to spend extra energy when reading and writing code The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 130/178
  • 131. Why you should avoid mutation? string = 'hello' do_something_with_string(string) puts string #=> ??? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 131/178
  • 132. Why you should avoid mutation? The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 132/178
  • 133. Ruby allows to mutate data The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 133/178
  • 134. Ruby allows to mutate data string = 'hello' string.upcase! puts string #=> "HELLO" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 134/178
  • 135. Ruby allows to mutate data array = [1, 2, 3] array << 4 puts array.inspect #=> [1, 2, 3, 4] array.unshift(0) puts array.inspect #=> [0, 1, 2, 3, 4] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 135/178
  • 136. Ruby allows to mutate data hash = { a: 1, b: 2, c: 3 } hash.merge!(d: 4) puts hash #=> {:a=>1, :b=>2, :c=>3, :d=>4} hash[:e] = 5 puts hash #=> {:a=>1, :b=>2, :c=>3, :d=>4, :e=>5} The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 136/178
  • 137. Immutability In Ruby The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 137/178
  • 138. Object#freeze The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 138/178
  • 139. Object#freeze Point = Struct.new(:x, :y) zero_point = Point.new(0, 0) zero_point.freeze zero_point.x = 1 #=> RuntimeError: can't modify frozen Point The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 139/178
  • 140. Object#freeze Point = Struct.new(:x, :y) zero_point = Point.new(0, 0) zero_point.freeze zero_point.x = 1 #=> RuntimeError: can't modify frozen Point The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 140/178
  • 141. Object#freeze languages = ['Ruby', 'Elixir'].freeze languages << 'Go' #=> RuntimeError: can't modify frozen Array languages[0].upcase! p languages #=> ["RUBY", "Elixir"] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 141/178
  • 142. Object#freeze languages = ['Ruby', 'Elixir'].freeze languages << 'Go' #=> RuntimeError: can't modify frozen Array languages[0].upcase! p languages #=> ["RUBY", "Elixir"] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 142/178
  • 143. Object#freeze languages = ['Ruby', 'Elixir'].freeze languages << 'Go' #=> RuntimeError: can't modify frozen Array languages[0].upcase! p languages #=> ["RUBY", "Elixir"] The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 143/178
  • 144. Frozen string literals in Ruby 2.3 The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 144/178
  • 145. Frozen string literals in Ruby 2.3 string = 'hello' string.upcase! puts string #=> HELLO The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 145/178
  • 146. Frozen string literals in Ruby 2.3 # frozen_string_literal: true string = 'hello' string.upcase! #=> RuntimeError: can't modify frozen String puts string #=> hello The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 146/178
  • 147. Frozen string literals in Ruby 2.3 # frozen_string_literal: true string = String.new('hello') string.upcase! puts string #=> 'HELLO' The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 147/178
  • 148. Frozen string literals in Ruby 2.3 # frozen_string_literal: true string = 'hello'.dup string.upcase! puts string #=> 'HELLO' The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 148/178
  • 149. Design classes to be immutable The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 149/178
  • 150. Design classes to be immutable class BlogPost attr_reader :title, :body def initialize(title:, body:) @title = title @body = body end def rename(new_title) BlogPost.new(title: new_title, body: body) end end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 150/178
  • 151. Design classes to be immutable class BlogPost attr_reader :title, :body def initialize(title:, body:) @title = title @body = body end def rename(new_title) BlogPost.new(title: new_title, body: body) end end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 151/178
  • 152. Design classes to be immutable class BlogPost attr_reader :title, :body def initialize(title:, body:) @title = title @body = body end def rename(new_title) BlogPost.new(title: new_title, body: body) end end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 152/178
  • 153. Design classes to be immutable post = BlogPost.new(title: 'Hi', body: 'This is my first post') #=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post"> renamed_post = post.rename('First Post') #=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post"> post.title #=> "Hi" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 153/178
  • 154. Design classes to be immutable post = BlogPost.new(title: 'Hi', body: 'This is my first post') #=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post"> renamed_post = post.rename('First Post') #=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post"> post.title #=> "Hi" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 154/178
  • 155. Design classes to be immutable post = BlogPost.new(title: 'Hi', body: 'This is my first post') #=> #<BlogPost:0x007f9ef20474d0 @title="Hi", @body="This is my first post"> renamed_post = post.rename('First Post') #=> #<BlogPost:0x007f9ef202ea20 @title="First Post", @body="This is my first post"> post.title #=> "Hi" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 155/178
  • 156. Persistent data structures The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 156/178
  • 157. Persistent data structures Persistent data structure is a data structure that always preserves the previous version of itself when it is modified. Such data structures are effectively immutable, as their operations do not (visibly) update the structure in-place, but instead always yield a new updated structure. — Wikipedia The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 157/178
  • 158. Hamster gem The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 158/178
  • 159. Hamster gem Efficient, immutable, and thread-safe collection classes for Ruby. Hamster provides 6 Persistent Data Structures: Hash, Vector, Set, SortedSet, List, and Deque (which works as an immutable queue or stack). The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 159/178
  • 160. Hamster::Hash require 'hamster/hash' john = Hamster::Hash[name: 'John', gender: :male] #=> Hamster::Hash[:name => "John", :gender => :male] john[:name] #=> "John" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 160/178
  • 161. Hamster::Hash require 'hamster/hash' peter = john.put(:name, 'Peter') #=> Hamster::Hash[:name => "Peter", :gender => :male] peter[:name] #=> "Peter" john[:name] #=> "John" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 161/178
  • 162. Hamster::Hash require 'hamster/hash' male = john.delete(:name) #=> Hamster::Hash[:gender => :male] male[:name] #=> nil john[:name] #=> "John" The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 162/178
  • 163. Why you should avoid mutation? » Mutation is a source of bugs » Mutation requires you to spend extra energy when reading and writing code The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 163/178
  • 164. Ruby has many functional features ! The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 164/178
  • 165. Ruby allows you to blend functional and OO approaches The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 165/178
  • 166. The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 166/178
  • 167. ...but Ruby is not a functional language ! The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 167/178
  • 168. Try to learn functional language The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 168/178
  • 169. Scala The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 169/178
  • 170. Clojure The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 170/178
  • 171. Haskell The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 171/178
  • 172. Elm The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 172/178
  • 173. Erlang The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 173/178
  • 174. Elixir The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 174/178
  • 175. Elixir defmodule Quicksort do def sort(list) when length(list) <= 1, do: list def sort(list) do [pivot | rest] = list {before_pivot, after_pivot} = split_relative_to_pivot(pivot, rest) merge_parts(pivot, sort(before_pivot), sort(after_pivot)) end defp split_relative_to_pivot(pivot, list) do Enum.split_with(list, fn(x) -> x < pivot end) end defp merge_parts(pivot, before_pivot, after_pivot) do before_pivot ++ [pivot | after_pivot] end end The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 175/178
  • 178. Happy hacking! ! The dark side of Ruby, or Learn functional programming with Ruby, by Evgeny Garlukovich 178/178