Closures in Ruby
Last Updated :
03 Jul, 2020
In Ruby, closure is a function or a block of code with variables that are bound to the environment that the closure is called. Or in other words, closure can be treated like a variable that can be assigned to another variable or can be pass to any function as an argument.
- A closure block can be defined in one scope and can be called in a different scope.
- Closure always remember the variable within its scope at the creation time and when its called it can access the variable even if they are not in the current scope i.e closure retain its knowledge of it lexical environment at the time of defining.
- In Ruby, Blocks, procs, lambdas are clousers.
Blocks
Blocks are the simplest form of Ruby closure. It is not an object but it is a piece of code which is enclosed in between braces {} or do…end.
- You can pass one or more variables into your block depending upon how the code block is written.
- You can use yield statement to call a block within a method with a value.
- It does not have their own name.
Syntax:
Using {}
block_name { #statements_to_be_executed }
Using do…end
block_name do
#statement-1
#statement-2
.
.
end
Example 1:
arr = [ 10 , 11 , 13 , 41 , 59 ]
arr. each do | item |
puts item
end
|
Output:
10
11
13
41
59
Example 2:
def print_once
puts "Hello! I am Method"
yield
end
print_once { puts "Hello! I am Block 1" }
def print_twice
yield
yield
end
print_twice { puts "Hello! I am Block 2" }
|
Output:
Hello! I am Method
Hello! I am Block 1
Hello! I am Block 2
Hello! I am Block 2
Explanation: In the above example, method name is print_once. First, the method statement is called which will display “Hello! I am Method. But as soon as yield statements execute the control goes to block and block will execute its statements and print “Hello! I am Method”. As soon as the block will execute it gives control back to the method and the method will continue to execute from where yield statement called. You can also use multiple yield statements in the single method as shown in the print_twice method.
Procs
Now the second type of ruby closure is Procs that is very much similar to block but with a few differences like a procs is assigned or store in a variable and it is executed by calling .call method. You can pass one or more proc to a method. As we know that block is not an object but Proc is an object. It is a block that turned into an object of the Proc class, that why the Proc looks similar to the instantiation of a class.
Syntax:
variableName = Proc.new {# Statement}
# Executing Procs
variableName.call
Example 1:
example = Proc . new { "GeeksforGeeks" }
puts example.call
|
Output:
GeeksforGeeks
Explanation: In the above example, we are assigning a block to an instance of the Proc class and assigning it to the variable, i.e., example and calling the method .call on it.
Example 2:
a = Proc . new {|x, y| "x = #{x}, y = #{y}" }
puts a.call( 1 , 2 )
puts a.call([ 2 , 1 ])
puts a.call( 3 , 4 , 8 )
puts a.call( 9 )
|
Output:
x = 1, y = 2
x = 2, y = 1
x = 3, y = 4
x = 9, y =
Explanation: In this example, we pass the argument in Proc using .call method. Procs accept arguments more generously. It filled missing arguments with nil and a single array arguments are deconstructed if the proc has multiple arguments. It does not give an error on extra arguments.
Lambda
We can say that lambda and Procs are kind of same there isn’t much difference. Also, we can say that a lambda is a way to define a block & its parameters with some special syntax. Lambda is like a regular method because they impose the number of parameters passed when they’re called and also they return like normal methods(It treat return keyword just like methods). If you pass a parameter to a lambda that doesn’t expect it, then you will get an ArgumentError.
Syntax:
variableName = -> {# Statement}
Example 1:
times_one = ->(x){ x * 2 }
puts times_one.call( 10 )
times_two = lambda{ "GeeksforGeeks" }
puts times_two.call
|
Output:
20
GeeksforGeeks
Example 2:
my_lambda = -> {puts "Hey" }
my_lambda_args = -> (x) {puts "Hello! " + x }
my_lambda.call
my_lambda_args.call( "GeeksforGeeks" )
|
Output:
Hey
Hello! GeeksforGeeks
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...