Closures in Ruby – Part1

Hello readers! welcome to my blog spot once again!

We all have come across Procs, Blocks, Lambdas and Methods in Ruby and have found them to be quite useful! but what are the differences between them? when to use each of them? In order to answer these questions we should first understand the concept of “Closures”. There are 2 parts in this blog: The first part explains about closures and the second part explains about Procs, Blocks and Lambdas in detail!

What are Closures ?

“In computer science, a closure is a first-class function with free variables that are bound in the lexical environment.”[1]

Let’s try to understand the terms used in the above definition! Firstly a closure is a first-class function. A first-class function is a function or a method that can be treated like an object and can be passed as a parameter to another method/function.

Secondly, because of their ability to be passed around like a parameter, closures retain the values of its local variables at the time of their creation and can access the values of the variables even when the closures are called out of the scope of the variables.

The following ruby code would be helpful to understand closures better:

# Add 2 strings

class Maths

def initialize(v1)

@v1 = v1

end

def sum(v2)

lambda { puts ” #{@v1}” + ” #{v2}”}

end

end

def call_closure(closure)

closure.call

end

num = Maths.new(“hi”)

var = num.sum(“hello”)

call_closure(var)

Output:

hi hello

In the above code, the method sum creates a closure using Lambdas. The parameter passed to this closure is ‘v2’ which is a local variable to the method ‘sum’. Now when the method sum is assigned to a variable ‘var’ as in the code “var = num.sum(“hello”) “, the method ‘sum’ returns the lambda and stores it into the variable var. Now this variable var is passed as a parameter to the method call_closure. This satisfies the first property of closures (first-class functions), the ability of a method to be passed like a parameter to another method. Inside the method call_closure the lambda is invoked and the value ‘v1’ and ‘v2’ is accessed even though they are out of scope in the method call_closure but within the lambda they are still alive. This satisfies the second property of retaining the values of the variables even though they are out of scope when the closure is called. In other words closures retain the knowledge of the variables in their lexical environment.

Not all programming languages support closures. In ruby closures are supported via Procs, Blocks and Lambdas. Programming languages implement closures in 2 ways:

  1. Closures create a copy of the variables when they are defined and are used where ever they are invoked.
  2. Closures keep a reference to the variables and access them where ever the closure is invoked.

Ruby uses the second method to retain the knowledge of its lexical environment. This would also mean that the values of these variables are susceptible to change inside the closure where ever it is passed. This can be both advantageous and disadvantageous. The advantage being: writing less code and following the DRY principle. The disadvantage being: These variables are not protected and can’t hold sensitive data and these variables are not eligible for garbage collection. Using too many of these variables might affect performance! Nevertheless closures are very handy and dynamic and can be very useful. The below ruby code would help us assess its pluses and minuses.

class Maths

def initialize(v1)

@v1 = v1

end

def square(closure)

p “The square of the number is: #{closure.call(@v1)}”

end

def change_square

lambda {

@v1 = @v1 + 1

p “The square of the changed number is: #{@v1**2}”

}

end

end

num = Maths.new(5)

num.square(lambda{|n| n**2} )

num.change_square.call

Output:

“The square of the number is: 25”

“The square of the changed number is: 36”

In the above code a closure is passed to the method ‘square’ to find the square of a number. The code can also be changed during the run time to perform other functions like finding the cube of the number or multiple of a number and so on. Thus closures are handy to execute any block of code, making the code highly flexible.

In Ruby closures keep a reference to the variables defined inside it as a result they are liable for change by other closures. For example in the above code, the method ‘change_square’ increments the value of @v1 and squares the result. The variable @v1 thus changes based on the code used inside the closure. Thus closures should be used with care. Now let’s look at the below code:

class Maths

def initialize(v1)

@v1 = v1

end

def multiple

lambda{

@v1 = @v1*2

p “The second multiple of the number is: #{@v1}”

}

end

end

num = Maths.new(5)

num.multiple.call

num.multiple.call

num.multiple.call

num.multiple.call

p “————–”

num1 = Maths.new(5)

num1.multiple.call

num1.multiple.call

Output:

“The second multiple of the number is: 10”

“The second multiple of the number is: 20”

“The second multiple of the number is: 40”

“The second multiple of the number is: 80”

“————–”

“The second multiple of the number is: 10”

“The second multiple of the number is: 20”

See how the same variable @v1 has been modified by closures called by 2 objects of the same class! Thus closures must be used with caution to avoid confusion and to protect data.

Hope you found this blog useful! Please feel free to share your comments. In the part-2 of this blog we will have a look at the four types of closures used in Ruby: The Procs, Blocks, Lambdas and methods. I thank Alan Skorkin and Robert Sosinski for inspiring me to write this blog

References:

1. Closure (computer science). (n.d.). , from http://www.princeton.edu/~achaney/tmve/wiki100k/docs/Closure_(computer_science).html

2. Alan Skorkin : “http://www.skorks.com/2010/05/closures-a-simple-explanation-using-ruby/

3. Robert Sonsinski: “http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

Advertisements

Leave a comment

Filed under Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s