Closures in Ruby
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:
# Ruby program to illustrate blocks arr = [ 10 , 11 , 13 , 41 , 59 ] arr. each do | item | puts item end |
Output:
10 11 13 41 59
Example 2:
# Ruby program to illustrate blocks # Method with single yield statement def print_once # statement of method puts "Hello! I am Method" # using yield statement yield end # Block 1 print_once { puts "Hello! I am Block 1" } # Method with two yield statement def print_twice # using yield statement yield yield end # Block 2 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:
# Ruby program to illustrate Procs # Creating proc example = Proc . new { "GeeksforGeeks" } # Executing proc # Using .call method 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:
# Ruby program to illustrate Procs # Creating proc a = Proc . new {|x, y| "x = #{x}, y = #{y}" } # Executing proc 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:
# Ruby program to illustrate lambda # Creating lambda times_one = ->(x){ x * 2 } # Displaying result puts times_one.call( 10 ) # Creating lambda times_two = lambda{ "GeeksforGeeks" } # Displaying result puts times_two.call |
Output:
20 GeeksforGeeks
Example 2:
# Ruby program to illustrate lambda # Creating lambda my_lambda = -> {puts "Hey" } # Creating lambda with argument my_lambda_args = -> (x) {puts "Hello! " + x } # Calling lambda my_lambda.call my_lambda_args.call( "GeeksforGeeks" ) |
Output:
Hey Hello! GeeksforGeeks
Please Login to comment...