SlideShare a Scribd company logo
Functional Objects
in Ruby
new horizons
Valentyn Ostakh
What is
Functional Object?
at first:
Object with
callable interface
Callable interface
#call
proc_fn = proc { |x| 1 + x }
lambda_fn = lambda { |x| 1 + x }
method_fn = 1.method(:+)
proc_fn.call(2) # => 3
lambda_fn.call(2) # => 3
method_fn.call(2) # => 3
Callable interface
Object + callable interface
class CallablePORO
def call
# TODO
end
def self.call
# TODO
end
end
CallablePORO.call
CallablePORO.new.call
Callable interface in action
Rack provides a minimal interface between webservers
that support Ruby and Ruby frameworks.
To use Rack, provide an object that responds to the call method.
secondly:
Object which
behave like functions
from FP
What is FP?
What is FP?
• programming paradigm

• stateless

• immutability

• evaluation of mathematical functions

• functions everywhere
FP concepts
• Purity

• Immutability

• Higher-order functions

• Closures

• Function Composition
• Point-Free Notation

• Currying

• Common Functional
Functions

• Referential Transparency
Purity
Purity
Pure Functions are very simple functions.
They only operate on their input parameters.
Pure Functions will always produce the same output given the same inputs.
Most useful Pure Functions must take at least one parameter.
All useful Pure Functions must return something.
Pure functions have no side effects.
Purity
z = 10
def sum(x, y)
x + y
end
def just10
10
end
Pure functions
Purity
z = 10
def sum(x, y)
x + y + z
end
def convert(file_name)
input = File.read(file_name)
output = JSON2YML.convert(input)
File.write('output.yml', output)
end
Impure functions
Purity
You don’t just write Pure Functions.
Since programs have to interface to the real world,
some parts of every program must be impure.
The goal is to minimize the amount of impure code
and segregate it from the rest of our program.
Immutability
Immutability
str = 'bite my shiny metal ass'
str.object_id # => 70317488591440
upper_str = str.upcase
upper_str # => "BITE MY SHINY METAL ASS"
upper_str.object_id # => 70317484572200
The simplest examples are the primitive objects:
Symbol, String, Integer, TrueClass(true), FalseClass(false), NilClass(nil) …
Immutability
Value Objects
• Small object that represents a simple entity whose equality is not based on identity
• Value objects have multiple attributes
• Attributes should be immutable throughout its life cycle
• Equality is determined by its attributes (and its type)
Immutability
There are no variables in Functional Programming.
Stored values are still called variables because of history but they are
constants, i.e. once x takes on a value, it’s that value for life.
x = 5
x = x + 1
In math, x can never be equal to x + 1
Higher-Order Functions
Higher-Order Functions
In Functional Programming, a function is a first-class citizen of the language.
In other words, a function is just another value.
Since functions are just values, we can pass them as parameters.
Higher-order Functions either take functions as parameters, return functions or both.
Higher-Order Functions
# returns value
values = [1, 2, 3, 4, 5]
values.map do |value|
value * value
end # => [1, 4, 9, 16, 25]
# returns function
def adder(a, b)
lambda { a + b }
end
adder_fn = adder(1, 2) # => #<Proc: (lambda)>
adder_fn.call # => 3
Closures
Closures
Techniques for implementing lexically scoped name binding
in languages with first-class functions
When a function is created, all of the variables in its scope at the time of
creation are accessible to it for the lifetime of the function.
A function exists as long as there still a reference to it.
A closure is a function’s scope that’s kept alive by a reference to that function.
Closures
outer = 1
def m
inner = 99
yield inner
puts "inner var = #{inner}"
end
m { |inner| outer += inner } # => 99
puts "outer var = #{outer}" # => 100
Functional Composition
Functional Composition
Code reuse sounds great but is difficult to achieve.
Make the code too specific and you can’t reuse it.
Make it too general and it can be too difficult to use in the first place.
So what we need is a balance between the two, a way to make smaller,
reusable pieces that we can use as building blocks
to construct more complex functionality.
Functional Composition
a = lambda { |x| x + 4 }
b = lambda { |y| y / 2 }
a.compose(b).call(4) #=> 6
b.compose(a).call(4) #=> 4
Functional Composition
add10 = -> value { value + 10 }
mult5 = -> value { value * 5 }
compose = -> (fn1, fn2) {
-> value { fn1.(fn2.(value)) }
}
add10mult5 = compose.(mult5, add10)
mult5add10 = compose.(add10, mult5)
add10mult5.(5) # => 75
mult5add10.(5) # => 35
Functional Composition
In math,  f ∘ g is functional composition and is read “f composed with g” or,
more commonly, “f after g”. So (f ∘ g)(x) is equivalent to calling  f after
calling g with x or simply,  f(g(x)).
Point-Free Notation
Point-Free Notation
A style of writing functions without having to specify the parameters.
First, we don’t have to specify redundant parameters. And since we don’t have to
specify them, we don’t have to think up names for all of them.
Second, it’s easier to read and reason about since it’s less verbose. This example is
simple, but imagine a function that took more parameters.
Tacit programming is a programming paradigm in which a function definition
does not include information regarding its arguments, using combinators and
function composition instead of variables
Point-Free Notation
tacit_string = :to_s.to_proc
def increment
self + 1
end
tacit_increment = :increment.to_proc
tacit_string.call(:Bender) # => "Bender"
tacit_increment.call(101) # => 102
Currying
Currying
Function decomposition.
A Curried Function is a function that only takes a single parameter at a time.
A Curried Function is a sequence of functions.
Currying
add = -> x, y { x + y }
native_curry = add.curry
curry_add = -> x { -> y { x + y } }
add.(5, 7) # => 12
native_curry.(5) # => #<Proc: (lambda)>
curry_add.(5) # => #<Proc: (lambda)>
native_curry.(5).(7) # => 12
curry_add.(5).(7) # => 12
Common Functional
Functions
Common Functional
Functions
This function is usually called fold in Functional Languages.
Higher-Order Functions for processing data structures
for building up new values.
Map, Reduce, Select, Find …
Functional Programming uses recursion to do looping.
Common Functional
Functions
values = [{k: :foo, v: 1}, {k: :bar, v: 2}, {k: :foo, v: 2}]
values.select { |value| value[:k] == :foo }
# => [{k: :foo, v: 1}, {k: :foo, v: 2}]
values.find { |value| value[:k] == :foo }
# => [{k: :foo, v: 1}]
values.reduce(0) { |m, value| m += value[:v] }
# => 5
Referential Transparency
Referential Transparency
Referential Transparency is a fancy term to describe
that a pure function can safely be replaced by its expression.
Referential Transparency
x = 3
x + 7 # => 10
3 + 7 # => 10
Not off all FP concepts
are applicable in Ruby
не все концепции из ФП
применимы к ООП

Правильнее будет сказать так, фп
языки построены на данных
концепциях, в этом их особенность,
В ОО языках мы можем лишь
имитировать данные концепции
New horizons
Purity + Object
Functional Object
Functional object abilities
• #call(input)

• no side-effects

• return some output
Callable object
class SurfaceGravity
attr_reader :weight
def initialize(weight)
@weight = weight
end
def call
weight * 9.8
end
end
weight_125 = SurfaceGravity.new(125)
weight_696 = SurfaceGravity.new(696)
weight_125.call # => 1225.0
weight_696.call # => 6820.8
Callable object
class SurfaceGravity
attr_reader :weight
def initialize(weight)
@weight = weight
end
def call
weight * 9.8
end
end
weight_125 = SurfaceGravity.new(125)
weight_696 = SurfaceGravity.new(696)
weight_125.call # => 1225.0
weight_696.call # => 6820.8
Achievements
• #call(input)

• no side-effects

• return some output
Functional object
class SurfaceGravity
def call(weight)
weight * 9.8
end
end
surface_gravity = SurfaceGravity.new
surface_gravity.call(125) # => 1225.0
surface_gravity.call(696) # => 6820.8
Functional object
class SurfaceGravity
def call(weight)
weight * 9.8
end
end
surface_gravity = SurfaceGravity.new
surface_gravity.call(125) # => 1225.0
surface_gravity.call(696) # => 6820.8
Achievements
• #call(input)

• no side-effects

• return some output
Callable Object
class LaunchShuttle
attr_reader :shuttle
def initialize(shuttle)
@shuttle = shuttle
end
def call
CheckFuelSystem.new(shuttle).call
ConfirmLaunchReady.new(shuttle).call
end
end
Callable Object
class LaunchShuttle
attr_reader :shuttle
def initialize(shuttle)
@shuttle = shuttle
end
def call
CheckFuelSystem.new(shuttle).call
ConfirmLaunchReady.new(shuttle).call
end
end
Achievements
• #call(input)

• no side-effects

• return some output
Functional Object
class LaunchShuttle
attr_reader :check_engines, :confirm_launch_ready
def initialize(check_engines:, confirm_launch_ready:)
@check_engines = check_engines
@confirm_launch_ready = confirm_launch_ready
end
def call(shuttle)
check_engines.call(shuttle)
confirm_launch_ready.call(shuttle)
end
end
Functional Object
class LaunchShuttle
attr_reader :check_engines, :confirm_launch_ready
def initialize(check_engines:, confirm_launch_ready:)
@check_engines = check_engines
@confirm_launch_ready = confirm_launch_ready
end
def call(shuttle)
check_engines.call(shuttle)
confirm_launch_ready.call(shuttle)
end
end
Achievements
• #call(input)

• no side-effects

• return some output
Functional Object
class LaunchShuttle
attr_reader :check_engines, :confirm_launch_ready
def initialize(check_engines:, confirm_launch_ready:)
@check_engines = check_engines
@confirm_launch_ready = confirm_launch_ready
end
def call(shuttle)
check_engines.call(shuttle)
confirm_launch_ready.call(shuttle)
end
end
Functional Object
launch_shuttle = LaunchShuttle.new(
check_engines: CheckEngines.new,
confirm_launch_ready: ConfirmLaunchReady.new
)
launch_shuttle.call(shuttle)
Discover Dependency
Injection
Single Responsibility
Open/closed
Liskov substitution
Interface segregation
Dependency inversion
Inversion of Control
container
Flow of control
Functional Object
class LaunchShuttle
attr_reader :check_engines, :confirm_launch_ready
def initialize(check_engines:, confirm_launch_ready:)
@check_engines = check_engines
@confirm_launch_ready = confirm_launch_ready
end
def call(shuttle)
check_engines.call(shuttle)
confirm_launch_ready.call(shuttle)
end
end
Achievements
• #call(input)

• side-effects under control

• return some output
Single Responsibility
Open/closed
Liskov substitution
Interface segregation
Dependency inversion
Single Responsibility
A class should have only one reason to change
Open / closed
Entities should be open for extension,
but closed for modification
Liskov substitution
Subtypes must be substitutable for their base types
Interface segregation
Many client-specific interfaces are better than one general-purpose interface
Dependency inversion
One should depend upon abstractions,
not concretions
Functional objects benefits
• simplicity

• reusability

• composition

• following SOLID

• architecture style
Inspired by
• Functional Architecture for the Practical Rubyist -
RedDotRubyConf 2017: https://www.youtube.com/watch?
time_continue=962&v=7qnsRejCyEQ

• Next Generation Ruby Web Appswith dry-rb, ROM, and Roda -
RedDotRubyConf 2016: https://www.youtube.com/watch?
v=6ecNAjVWqaI

• Full Stack Fest 2015: Blending Functional and OO Programming
in Ruby, by Piotr Solnica: https://www.youtube.com/watch?
v=rMxurF4oqsc

• RubyConf 2017: 4 Programming Paradigms in 45 Minutes by Aja
Hammerly: https://www.youtube.com/watch?v=3TBq__oKUzk
Thank you!
Questions?

More Related Content

PDF
Functions in C++
PPTX
Functions in c++
PDF
Thinking in Functions: Functional Programming in Python
PPTX
Function class in c++
PPTX
Functions in C++
PPTX
Python programming: Anonymous functions, String operations
PPT
Scala functions
PPT
C++ Functions
Functions in C++
Functions in c++
Thinking in Functions: Functional Programming in Python
Function class in c++
Functions in C++
Python programming: Anonymous functions, String operations
Scala functions
C++ Functions

What's hot (20)

PPSX
DIWE - Advanced PHP Concepts
PDF
Intro to functional programming
PPT
Introduction To Functional Programming
PPT
C++ functions
PDF
Intro to functional programming
PPTX
Functions in c++
PDF
Practical Functional Programming Presentation by Bogdan Hodorog
PPT
Functions in c++
PPTX
Functional programming in JavaScript
PDF
Scala categorytheory
ODP
Clojure basics
PDF
An Introduction to Functional Programming - DeveloperUG - 20140311
PPTX
Inline Functions and Default arguments
PPT
C++ functions
PPT
Introduction to Functional Programming in JavaScript
PPT
16717 functions in C++
 
PDF
Functional Python Webinar from October 22nd, 2014
PPT
Unit 6 pointers
PPTX
Functions in python slide share
PPTX
Inline function
DIWE - Advanced PHP Concepts
Intro to functional programming
Introduction To Functional Programming
C++ functions
Intro to functional programming
Functions in c++
Practical Functional Programming Presentation by Bogdan Hodorog
Functions in c++
Functional programming in JavaScript
Scala categorytheory
Clojure basics
An Introduction to Functional Programming - DeveloperUG - 20140311
Inline Functions and Default arguments
C++ functions
Introduction to Functional Programming in JavaScript
16717 functions in C++
 
Functional Python Webinar from October 22nd, 2014
Unit 6 pointers
Functions in python slide share
Inline function
Ad

Similar to Functional Objects in Ruby: new horizons – Valentine Ostakh (20)

PPTX
Functional programming with Ruby - can make you look smart
ODP
Functions & Closures in Scala
ODP
Functions & Closures in Scala
ODP
Functions & closures
PPTX
use of Functions to write python program.pptx
PDF
Notes5
PPT
Functional Programming - Past, Present and Future
PPT
Functional Programming Past Present Future
PPTX
Functions in Python Programming Language
PDF
Programming in Scala - Lecture Two
PPTX
UNIT-02-pythonfunctions python function using detehdjsjehhdjejdhdjdjdjddjdhdhhd
PPTX
Pythonlearn-04-Functions (1).pptx
PPTX
Python Learn Function with example programs
PPTX
OOPS Object oriented Programming PPT Tutorial
PPTX
2_3 Functions 5d.pptx2_3 Functions 5d.pptx
ODP
Functional programming with Scala
PDF
Functions_21_22.pdf
PPTX
Functions in python, types of functions in python
PPTX
Lecture 08.pptx
PPT
04_python_functions.ppt You can define functions to provide the required func...
Functional programming with Ruby - can make you look smart
Functions & Closures in Scala
Functions & Closures in Scala
Functions & closures
use of Functions to write python program.pptx
Notes5
Functional Programming - Past, Present and Future
Functional Programming Past Present Future
Functions in Python Programming Language
Programming in Scala - Lecture Two
UNIT-02-pythonfunctions python function using detehdjsjehhdjejdhdjdjdjddjdhdhhd
Pythonlearn-04-Functions (1).pptx
Python Learn Function with example programs
OOPS Object oriented Programming PPT Tutorial
2_3 Functions 5d.pptx2_3 Functions 5d.pptx
Functional programming with Scala
Functions_21_22.pdf
Functions in python, types of functions in python
Lecture 08.pptx
04_python_functions.ppt You can define functions to provide the required func...
Ad

More from Ruby Meditation (20)

PDF
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
PDF
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
PDF
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
PDF
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
PDF
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
PDF
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
PDF
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
PDF
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
PDF
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
PDF
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
PDF
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
PDF
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
PDF
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
PDF
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
PDF
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
PDF
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
PDF
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
PDF
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
PDF
Rails App performance at the limit - Bogdan Gusiev
PDF
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Rails App performance at the limit - Bogdan Gusiev
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23

Recently uploaded (20)

PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Approach and Philosophy of On baking technology
PPTX
Big Data Technologies - Introduction.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Empathic Computing: Creating Shared Understanding
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
cuic standard and advanced reporting.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
The Rise and Fall of 3GPP – Time for a Sabbatical?
Mobile App Security Testing_ A Comprehensive Guide.pdf
Approach and Philosophy of On baking technology
Big Data Technologies - Introduction.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
MIND Revenue Release Quarter 2 2025 Press Release
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Unlocking AI with Model Context Protocol (MCP)
Review of recent advances in non-invasive hemoglobin estimation
Empathic Computing: Creating Shared Understanding
The AUB Centre for AI in Media Proposal.docx
Understanding_Digital_Forensics_Presentation.pptx
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Advanced methodologies resolving dimensionality complications for autism neur...
cuic standard and advanced reporting.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Building Integrated photovoltaic BIPV_UPV.pdf

Functional Objects in Ruby: new horizons – Valentine Ostakh

  • 1. Functional Objects in Ruby new horizons Valentyn Ostakh
  • 5. proc_fn = proc { |x| 1 + x } lambda_fn = lambda { |x| 1 + x } method_fn = 1.method(:+) proc_fn.call(2) # => 3 lambda_fn.call(2) # => 3 method_fn.call(2) # => 3 Callable interface
  • 6. Object + callable interface class CallablePORO def call # TODO end def self.call # TODO end end CallablePORO.call CallablePORO.new.call
  • 7. Callable interface in action Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks. To use Rack, provide an object that responds to the call method.
  • 10. What is FP? • programming paradigm • stateless • immutability • evaluation of mathematical functions • functions everywhere
  • 11. FP concepts • Purity • Immutability • Higher-order functions • Closures • Function Composition • Point-Free Notation • Currying • Common Functional Functions • Referential Transparency
  • 13. Purity Pure Functions are very simple functions. They only operate on their input parameters. Pure Functions will always produce the same output given the same inputs. Most useful Pure Functions must take at least one parameter. All useful Pure Functions must return something. Pure functions have no side effects.
  • 14. Purity z = 10 def sum(x, y) x + y end def just10 10 end Pure functions
  • 15. Purity z = 10 def sum(x, y) x + y + z end def convert(file_name) input = File.read(file_name) output = JSON2YML.convert(input) File.write('output.yml', output) end Impure functions
  • 16. Purity You don’t just write Pure Functions. Since programs have to interface to the real world, some parts of every program must be impure. The goal is to minimize the amount of impure code and segregate it from the rest of our program.
  • 18. Immutability str = 'bite my shiny metal ass' str.object_id # => 70317488591440 upper_str = str.upcase upper_str # => "BITE MY SHINY METAL ASS" upper_str.object_id # => 70317484572200 The simplest examples are the primitive objects: Symbol, String, Integer, TrueClass(true), FalseClass(false), NilClass(nil) …
  • 19. Immutability Value Objects • Small object that represents a simple entity whose equality is not based on identity • Value objects have multiple attributes • Attributes should be immutable throughout its life cycle • Equality is determined by its attributes (and its type)
  • 20. Immutability There are no variables in Functional Programming. Stored values are still called variables because of history but they are constants, i.e. once x takes on a value, it’s that value for life. x = 5 x = x + 1 In math, x can never be equal to x + 1
  • 22. Higher-Order Functions In Functional Programming, a function is a first-class citizen of the language. In other words, a function is just another value. Since functions are just values, we can pass them as parameters. Higher-order Functions either take functions as parameters, return functions or both.
  • 23. Higher-Order Functions # returns value values = [1, 2, 3, 4, 5] values.map do |value| value * value end # => [1, 4, 9, 16, 25] # returns function def adder(a, b) lambda { a + b } end adder_fn = adder(1, 2) # => #<Proc: (lambda)> adder_fn.call # => 3
  • 25. Closures Techniques for implementing lexically scoped name binding in languages with first-class functions When a function is created, all of the variables in its scope at the time of creation are accessible to it for the lifetime of the function. A function exists as long as there still a reference to it. A closure is a function’s scope that’s kept alive by a reference to that function.
  • 26. Closures outer = 1 def m inner = 99 yield inner puts "inner var = #{inner}" end m { |inner| outer += inner } # => 99 puts "outer var = #{outer}" # => 100
  • 28. Functional Composition Code reuse sounds great but is difficult to achieve. Make the code too specific and you can’t reuse it. Make it too general and it can be too difficult to use in the first place. So what we need is a balance between the two, a way to make smaller, reusable pieces that we can use as building blocks to construct more complex functionality.
  • 29. Functional Composition a = lambda { |x| x + 4 } b = lambda { |y| y / 2 } a.compose(b).call(4) #=> 6 b.compose(a).call(4) #=> 4
  • 30. Functional Composition add10 = -> value { value + 10 } mult5 = -> value { value * 5 } compose = -> (fn1, fn2) { -> value { fn1.(fn2.(value)) } } add10mult5 = compose.(mult5, add10) mult5add10 = compose.(add10, mult5) add10mult5.(5) # => 75 mult5add10.(5) # => 35
  • 31. Functional Composition In math,  f ∘ g is functional composition and is read “f composed with g” or, more commonly, “f after g”. So (f ∘ g)(x) is equivalent to calling  f after calling g with x or simply,  f(g(x)).
  • 33. Point-Free Notation A style of writing functions without having to specify the parameters. First, we don’t have to specify redundant parameters. And since we don’t have to specify them, we don’t have to think up names for all of them. Second, it’s easier to read and reason about since it’s less verbose. This example is simple, but imagine a function that took more parameters. Tacit programming is a programming paradigm in which a function definition does not include information regarding its arguments, using combinators and function composition instead of variables
  • 34. Point-Free Notation tacit_string = :to_s.to_proc def increment self + 1 end tacit_increment = :increment.to_proc tacit_string.call(:Bender) # => "Bender" tacit_increment.call(101) # => 102
  • 36. Currying Function decomposition. A Curried Function is a function that only takes a single parameter at a time. A Curried Function is a sequence of functions.
  • 37. Currying add = -> x, y { x + y } native_curry = add.curry curry_add = -> x { -> y { x + y } } add.(5, 7) # => 12 native_curry.(5) # => #<Proc: (lambda)> curry_add.(5) # => #<Proc: (lambda)> native_curry.(5).(7) # => 12 curry_add.(5).(7) # => 12
  • 39. Common Functional Functions This function is usually called fold in Functional Languages. Higher-Order Functions for processing data structures for building up new values. Map, Reduce, Select, Find … Functional Programming uses recursion to do looping.
  • 40. Common Functional Functions values = [{k: :foo, v: 1}, {k: :bar, v: 2}, {k: :foo, v: 2}] values.select { |value| value[:k] == :foo } # => [{k: :foo, v: 1}, {k: :foo, v: 2}] values.find { |value| value[:k] == :foo } # => [{k: :foo, v: 1}] values.reduce(0) { |m, value| m += value[:v] } # => 5
  • 42. Referential Transparency Referential Transparency is a fancy term to describe that a pure function can safely be replaced by its expression.
  • 43. Referential Transparency x = 3 x + 7 # => 10 3 + 7 # => 10
  • 44. Not off all FP concepts are applicable in Ruby не все концепции из ФП применимы к ООП Правильнее будет сказать так, фп языки построены на данных концепциях, в этом их особенность, В ОО языках мы можем лишь имитировать данные концепции
  • 48. Functional object abilities • #call(input) • no side-effects • return some output
  • 49. Callable object class SurfaceGravity attr_reader :weight def initialize(weight) @weight = weight end def call weight * 9.8 end end weight_125 = SurfaceGravity.new(125) weight_696 = SurfaceGravity.new(696) weight_125.call # => 1225.0 weight_696.call # => 6820.8
  • 50. Callable object class SurfaceGravity attr_reader :weight def initialize(weight) @weight = weight end def call weight * 9.8 end end weight_125 = SurfaceGravity.new(125) weight_696 = SurfaceGravity.new(696) weight_125.call # => 1225.0 weight_696.call # => 6820.8
  • 51. Achievements • #call(input) • no side-effects • return some output
  • 52. Functional object class SurfaceGravity def call(weight) weight * 9.8 end end surface_gravity = SurfaceGravity.new surface_gravity.call(125) # => 1225.0 surface_gravity.call(696) # => 6820.8
  • 53. Functional object class SurfaceGravity def call(weight) weight * 9.8 end end surface_gravity = SurfaceGravity.new surface_gravity.call(125) # => 1225.0 surface_gravity.call(696) # => 6820.8
  • 54. Achievements • #call(input) • no side-effects • return some output
  • 55. Callable Object class LaunchShuttle attr_reader :shuttle def initialize(shuttle) @shuttle = shuttle end def call CheckFuelSystem.new(shuttle).call ConfirmLaunchReady.new(shuttle).call end end
  • 56. Callable Object class LaunchShuttle attr_reader :shuttle def initialize(shuttle) @shuttle = shuttle end def call CheckFuelSystem.new(shuttle).call ConfirmLaunchReady.new(shuttle).call end end
  • 57. Achievements • #call(input) • no side-effects • return some output
  • 58. Functional Object class LaunchShuttle attr_reader :check_engines, :confirm_launch_ready def initialize(check_engines:, confirm_launch_ready:) @check_engines = check_engines @confirm_launch_ready = confirm_launch_ready end def call(shuttle) check_engines.call(shuttle) confirm_launch_ready.call(shuttle) end end
  • 59. Functional Object class LaunchShuttle attr_reader :check_engines, :confirm_launch_ready def initialize(check_engines:, confirm_launch_ready:) @check_engines = check_engines @confirm_launch_ready = confirm_launch_ready end def call(shuttle) check_engines.call(shuttle) confirm_launch_ready.call(shuttle) end end
  • 60. Achievements • #call(input) • no side-effects • return some output
  • 61. Functional Object class LaunchShuttle attr_reader :check_engines, :confirm_launch_ready def initialize(check_engines:, confirm_launch_ready:) @check_engines = check_engines @confirm_launch_ready = confirm_launch_ready end def call(shuttle) check_engines.call(shuttle) confirm_launch_ready.call(shuttle) end end
  • 62. Functional Object launch_shuttle = LaunchShuttle.new( check_engines: CheckEngines.new, confirm_launch_ready: ConfirmLaunchReady.new ) launch_shuttle.call(shuttle)
  • 67. Functional Object class LaunchShuttle attr_reader :check_engines, :confirm_launch_ready def initialize(check_engines:, confirm_launch_ready:) @check_engines = check_engines @confirm_launch_ready = confirm_launch_ready end def call(shuttle) check_engines.call(shuttle) confirm_launch_ready.call(shuttle) end end
  • 68. Achievements • #call(input) • side-effects under control • return some output
  • 70. Single Responsibility A class should have only one reason to change
  • 71. Open / closed Entities should be open for extension, but closed for modification
  • 72. Liskov substitution Subtypes must be substitutable for their base types
  • 73. Interface segregation Many client-specific interfaces are better than one general-purpose interface
  • 74. Dependency inversion One should depend upon abstractions, not concretions
  • 75. Functional objects benefits • simplicity • reusability • composition • following SOLID • architecture style
  • 76. Inspired by • Functional Architecture for the Practical Rubyist - RedDotRubyConf 2017: https://www.youtube.com/watch? time_continue=962&v=7qnsRejCyEQ • Next Generation Ruby Web Appswith dry-rb, ROM, and Roda - RedDotRubyConf 2016: https://www.youtube.com/watch? v=6ecNAjVWqaI • Full Stack Fest 2015: Blending Functional and OO Programming in Ruby, by Piotr Solnica: https://www.youtube.com/watch? v=rMxurF4oqsc • RubyConf 2017: 4 Programming Paradigms in 45 Minutes by Aja Hammerly: https://www.youtube.com/watch?v=3TBq__oKUzk