Blocks, Procs and Lambdas
Date: Jan 22, 2015
Ruby's Methods
Before start talking about Blocks, Procs and Lambdas, maybe it is worth to see why ruby is called an "Object-Oriented" Language
While I was learning about how to use ruby's Class, it becomes NOT so clear that why we use Class and why it is so special? And why suddenly everyone talks about 'object oriented language'? When I deal with String and Fixnum - this was much easier for me to undertnad that 'object' means. Objects have behavior and may contain data, data to which they alone control access.
Blocks
Blocks are one of ruby's most powerful features. In fact, blocks are actually a type of 'syntax' in the ruby language. They are a little bit different from objects and method definitions. Blocks are one of the very few exceptions to the "everything is an object" rule in Ruby. Blocks are not objects, and they can't be saved to variables. block can be expressed by 'do...end' or { }. Passing blocks is one way to pass functions as arguments to other functions. The difference is that the curly braces have a higher priority inside of the ruby interpreter.
# example 1
def print(&block)
puts "hello world"
block.call
end
puts print{puts "hello again"}
# example 2
def some_adding(a, b, my_proc)
my_block.call(a, b)
end
add = proc { |x, y| x + y }
some_adding(8, 9, add) #=> 25
# The block is expressed with '&'. It doesn't execute unless you 'call' them
# The proc add is passed as a parameter to the method some_adding.
This example itself isn't very useful unless we like to explore many different ways to print out stuff. The reason block is a powerful tool is that there are many useful 'keywords' like 'BEGIN', 'END', 'rescue', 'raise' and 'ensure'. Let's see some examples
# EXAMPLE 1. rescue, ensure, raise, BEGIN and END
def header(&block)
puts "I am a header"
block.call
# rescue block will rescue from 'raised' error thus error message will not be printed
rescue
puts "This is a rescue!!"
# No matter what happens 'ensure' block will run after error message
ensure
puts "This is the last sentence"
end
header { puts "This is inside of the header"
raise "This is an error message"
message and it will stop code running forward
}
BEGIN {puts "THIS IS FROM BEGIN BLOCK"}
END {puts "THIS IS END BLOCK"}
=>
THIS IS FROM BEGIN BLOCK
I am a header
This is inside of the header
This is a rescue!!
This is the last sentence
THIS IS END BLOCK
Here is also way to use begin-end block. It can be expressed as a simple block of code.
Yield
You invoke a block by using the yield statement. You can pass the argument(parameters) for invoking the block. Let's see the example. In this example, 'name' is given as a parameters for invoking call_name block. You can pass as many parameters you wish and it can be used in block between two pipes("||", in this case "|name|").
def call_name(&block)
puts "What is your name?"
yield name = gets.chomp
end
call_name { |name|
puts "Your name in upcase is #{name.upcase}"
puts "Your name is #{name}"
}
=>
What is your name?
sarah
Your name in upcase is SARAH
Your name is sarah
The great thing about 'yield' statment is that it gives control of the current method over the block that is passed in. Yield can also be used to send a variable value in to, or out of, a block of code. It also does not change the original variable so although the 'name' variable is same it will not upcase the original name 'sarah'.
# Example3. This is how we can use block in real life
class Speech
attr :title
def initialize
print "What is the speech title?"
@title = gets.chomp
@lines = []
while add_line
puts "Line added."
end
end
def add_line
puts "Add line: (blank line to exit)"
line = gets.chomp
if line.length > 0
@lines << line
return line
else
return nil
end
end
def each(&block)
@lines.each { |line| yield line }
end
end
my_speech = Speech.new
my_speech.each {|line| puts "#{my_speech.title} : #{line}" }
=>
What is the speech title?Test Speech
Add line: (blank line to exit)
Sarah is awesome person.
Line added.
Add line: (blank line to exit)
Sarah is going to be an awesome programmer.
Line added.
Add line: (blank line to exit)
Test Speech : Sarah is awesome person.
Test Speech : Sarah is going to be an awesome programmer.
One very important lesson here. If you forget to put attr :title, this code will not run and give you error on undefined local veriable or method 'title'. Very important to put attr reader if you want to call the method outside of the class.
Procs and Lambdas
Proc objects are blocks of code that can be bound to a set of local variables. You can think of a proc object as a "saved" block. Procs are a great way of keeping your code DRY.
They are blocks of code that can be assigned to variables. Proc (short for Process) is more meaningful and broad concept including blocks and lambdas. Therefore many rubist write in uupcase 'Procs' but in lowercase 'blocks' and 'lambdas'. It is also because blocks and lambdas do not have their own class.
#How to create procs
my_proc = Proc.new {} # or
=> #< Proc:0x007fa2790e5dd0@(irb):15 >
my_proc = proc # No argument will cause Argument Error.
=> ArgumentError: tried to create Proc object without a block
my_proc = proc {}
=> #< Proc:0x007fa278b1ecf8@(irb):18 >
multifying = proc { |x| x.inject(&:+) }
multifying.call([1,2,3]) #=> 6proc_square_number = proc { |x| x * x }
proc_sum_array = proc { |x| x.inject(&:+) }
#How to create lambdas
my_lambda = lambda {} # or
my_lambda -> lambda {} #'skinny arrow' can be used to create lambdas
=> #< Proc:0x007fa278b2fdf0@(irb):20 (lambda) > #Difference when you create lambda is that it will say (lambda).
Here is a example of using skinny lambda in model scope. The important component is the "-> {}"
So why use Procs and lambda? Basically they are 'keywords'. Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables. This is probably how Ruby's class and its instance variables are set.
class AddressBook
def initialize(&block)
yield self if block_given?
end
def set_variable
return proc { |kind, value| [kind, value].join(": ") }
end
def name(value)
@name = set_variable.call "Name", value
end
def phone_number(value)
@phone_number= set_variable.call "Phone_Number", value
end
def e_mail(value)
@e_mail = set_variable.call "E-Mail", value
end
def display
puts @name
puts "_____________"
puts @phone_number
puts "_____________"
puts @e_mail
puts "_____________"
end
end
brian_addressbook = AddressBook.new { |a|
a.name "Brian theDog"
a.phone_number "777-666-5555"
a.e_mail "brian@thedog.com"
}
brian_addressbook.display
=>
Name: Brian theDog
_____________
Phone_Number: 777-666-5555
_____________
E-Mail: brian@thedog.com
_____________
Difference between procs and lambda is that when you call
procs : It returns from inside of procs
lambdas : It has diminutive return like Ruby. While proc return will stop a method and return the value provided (inside of the proc), lambdas will return their value TO the method and let the method continues on.
def procs_return
variable = proc {return "I am procs and this is from the inside of procs"}
variable.call
return "This is from outside of the procs_return method"
end
def lambdas_return
variable = lambda {return "I am lambda and this is from the inside of lambda"}
variable.call
return "This is from outside of the lambda_return method"
end
puts procs_return
puts "___________"
puts lambdas_return
=>
I am procs and this is from the inside of procs
___________
This is from outside of the lambda_return method
# proc will return inside of proc
# lambda will continue the method and return the final return
Closure
Blocks, Procs and Lambdas are closures in Ruby. Closure is a function/method that can be passed around like an object and remembers the value of variables no longer in scope.
Ruby's Methods
Before start talking about Blocks, Procs and Lambdas, maybe it is worth to see why ruby is called an "Object-Oriented" Language
While I was learning about how to use ruby's Class, it becomes NOT so clear that why we use Class and why it is so special? And why suddenly everyone talks about 'object oriented language'? When I deal with String and Fixnum - this was much easier for me to undertnad that 'object' means. Objects have behavior and may contain data, data to which they alone control access.
Blocks
Blocks are one of ruby's most powerful features. In fact, blocks are actually a type of 'syntax' in the ruby language. They are a little bit different from objects and method definitions. Blocks are one of the very few exceptions to the "everything is an object" rule in Ruby. Blocks are not objects, and they can't be saved to variables. block can be expressed by 'do...end' or { }. Passing blocks is one way to pass functions as arguments to other functions. The difference is that the curly braces have a higher priority inside of the ruby interpreter.
This example itself isn't very useful unless we like to explore many different ways to print out stuff. The reason block is a powerful tool is that there are many useful 'keywords' like 'BEGIN', 'END', 'rescue', 'raise' and 'ensure'. Let's see some examples
Here is also way to use begin-end block. It can be expressed as a simple block of code.
Yield
You invoke a block by using the yield statement. You can pass the argument(parameters) for invoking the block. Let's see the example. In this example, 'name' is given as a parameters for invoking call_name block. You can pass as many parameters you wish and it can be used in block between two pipes("||", in this case "|name|").
The great thing about 'yield' statment is that it gives control of the current method over the block that is passed in. Yield can also be used to send a variable value in to, or out of, a block of code. It also does not change the original variable so although the 'name' variable is same it will not upcase the original name 'sarah'.
One very important lesson here. If you forget to put attr :title, this code will not run and give you error on undefined local veriable or method 'title'. Very important to put attr reader if you want to call the method outside of the class.
Procs and Lambdas
Proc objects are blocks of code that can be bound to a set of local variables. You can think of a proc object as a "saved" block. Procs are a great way of keeping your code DRY.
They are blocks of code that can be assigned to variables. Proc (short for Process) is more meaningful and broad concept including blocks and lambdas. Therefore many rubist write in uupcase 'Procs' but in lowercase 'blocks' and 'lambdas'. It is also because blocks and lambdas do not have their own class.
Here is a example of using skinny lambda in model scope. The important component is the "-> {}"
So why use Procs and lambda? Basically they are 'keywords'. Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables. This is probably how Ruby's class and its instance variables are set.
Difference between procs and lambda is that when you call procs : It returns from inside of procs lambdas : It has diminutive return like Ruby. While proc return will stop a method and return the value provided (inside of the proc), lambdas will return their value TO the method and let the method continues on.
Closure
Blocks, Procs and Lambdas are closures in Ruby. Closure is a function/method that can be passed around like an object and remembers the value of variables no longer in scope.