Anonymous functions and closures are a useful concepts included in most modern programming languages. Like so many elements of modern programming, the closure has its origins in the early Lisps.
Anonymous functions are used heavily in JavaScript for many things, most notably the many callbacks used by the language’s many frameworks. In Ruby we see them most often in their block format.
First let’s look at anonymous functions. An anonymous function allows a developer to create a function that has no name. In other words anonymous functions can be used to store a bit of functionality in a variable and pass that piece of functionality around. First let’s look at an example using an anonymous function in Ruby and JavaScript:
[1, 2, 3].map do |number_to_double|
number_to_double * 2
end
_.map([1, 2, 3], function(numberToDouble) {
return numberToDouble * 2
})
Above we use the Ruby Array‘s map method and the JavaScript library
Lo-Dash’s map method. In
both cases we provide a callback. The Ruby example uses a block and the
JavaScript example uses a function. These callbacks are anonymous functions. We
specify a bit of functionality, in this case multiplying the number provided by
two, and then pass that functionality to the map method. In our example the
resulting array would be [2, 4, 6]. Because we’re allowed to define the
functionality we want to use to modify the elements of our array it makes it
much easier to create reusable code. As opposed to creating many different map
methods, each that modified the contents of the array in a different way, we
only need one that allows us to provide it with the functionality our specific
use case requires.
Closures have to do with the connection between functionality and the variables that are available to said functionality when it’s executed. When a closure is created it can reference any of the variables available in its lexical scope and as a result is said to close over its environment. This raises the question, what is a lexical scope? Lexical scoping simply means that variables refer to their local environment.
Let’s look at an example to help clarify:
Ruby lexical scoping
def lexical_scope_example(multiplier)
[1, 2, 3].map do |number|
new_number_to_double = number * multiplier
new_number_to_double * 2
end
end
> lexical_scope_example(5)
=> [10, 20, 30]
In our Ruby example we have two lexical scopes:
- The
lexical_scope_examplefunction has the parametermultiplier - The block we pass to the
mapmethod can access themultiplier,numberandnew_number_to_doublevariables
JavaScript lexical scoping
function lexicalScopeExample(multiplier) {
return _.map([1, 2, 3], function(number) {
var newNumberToDouble = number * multiplier
return newNumberToDouble * 2
});
}
> lexicalScopeExample(5)
=> [10, 20, 30]
In our JavaScript example we have two lexical scopes:
- The
lexicalScopeExamplefunction has the parametermultiplier - The block we pass to the
mapmethod can access themultiplier,numberandnewNumberToDoublevariables
It’s interesting to note that the block’s lexical scope includes the variables
which belong to the lexical scope it is created in. The inverse is not true.
Variables defined in the block’s lexical scope are not then available to the
function’s lexical scope. Let’s take a look at what happens if we try to access
the new_number_to_double variable outside of the block’s lexical scope. In
this case our anonymous function has closed over its environment.
Ruby variable outside of block’s scope
def lexical_scope_example(multiplier)
[1, 2, 3].map do |number|
new_number_to_double = number * multiplier
new_number_to_double * 2
end
puts new_number_to_double
end
> lexical_scope_example(5)
=> NameError: undefined local variable or method `new_number_to_double' for main:Object
JavaScript variable outside of block’s scope
function lexicalScopeExample(multiplier) {
return _.map([1, 2, 3], function(number) {
var newNumberToDouble = number * multiplier
return newNumberToDouble * 2
});
console.log(newNumberToDouble)
}
> lexicalScopeExample(5)
=> ReferenceError: newNumberToDouble is not defined
Now that we’ve taken a look at lexical scope let’s revisit how they pertain to closures. Closures allows us to define units of functionality while maintaining references to all the variables that exist in the lexical scope they are defined. These units of functionality can then be executed in a different lexical scope. Let’s take a look at an example.
Ruby in different lexical scope
def scope_two
yield
end
def scope_one
closure_addend = 3
scope_two do
closure_addend += 5
end
puts "The variable in our main lexical scope after the method is executed
equals #{closure_addend}"
end
> scope_one
=> "The variable in our main lexical scope after the method is executed equals 8"
In our Ruby example we have three lexical scopes:
- The
scope_onefunction includes theclosure_addendvariable - The block we define when we call the
scope_twofunction includes theclosure_addendvariables
Let’s walk through the Ruby version step by step:
- In irb we call our
scope_onefunction - Within this function we create the
closure_addendvariable and assign it the value of 3 - Within the lexical scope of our
scope_onefunction we define a block and pass it to thescope_twofunction - Inside the new lexical scope of the
scope_twofunction we execute our closure - Inside of our closure we add 5 to the
closure_addendvariable we defined within the lexical scope of thescope_onefunction - We then return to our
scope_onelexical scope andputsourclosure_addendvariable, which has now been incremented by 5
JavaScript in different lexical scope
function scopeTwo(callback) {
callback();
}
function scopeOne() {
var closureAddend = 3;
scopeTwo(function() {
closureAddend = closureAddend + 5;
});
console.log("The variable in our main lexical scope after the method is
executed " + closureAddend);
}
> scopeOne()
=> "The variable in our main lexical scope after the method is executed equals 8"
In our JavaScript example we have three lexical scopes:
- The
scopeOnefunction includes theclosureAddendvariable - The function (closure) we pass when we call the
scopeTwofunction includes theclosureAddendvariables
Let’s walk through the JavaScript version step by step:
- In the browser console we call our
scopeOnefunction - Within this function we create the
closureAddendvariable and assign it the value of 3 - Within the lexical scope of our
scopeOnefunction we define a function and pass it to thescopeTwofunction - Inside the new lexical scope of the
scopeTwofunction we execute our closure that we calledcallback - Inside of our closure we add 5 to the
closureAddendvariable we defined within the lexical scope of thescopeOnefunction - We then return to our
scopeOnelexical scope and log ourclosureAddendvariable, which has now been incremented by 5
The interesting part of this is that our closure gets executed in a completely different lexical scope than it was created in, but still has access to the variables in the original scope. It’s also important to notice that the modifications that occur in the new lexical scope affect original value, because it is the same value.
Let’s take a look at what would happen if we attempted to access the
closure_addend variable in the scope_two function’s lexical scope.
Ruby variable in other method’s scope
def scope_two
yield
puts "We just modified this variable in the block above #{closure_addend}"
end
def scope_one
closure_addend = 3
scope_two do
closure_addend += 5
end
puts "The variable in our main lexical scope after the method is executed #{closure_addend}"
end
> scope_one
=> `scope_two': undefined local variable or method `closure_addend'
for main:Object (NameError)
JavaScript variable in other method’s scope
function scopeTwo(callback) {
callback();
console.log("We just modified this variable in the block above " + closureAddend);
}
function scopeOne() {
var closureAddend = 3;
scopeTwo(function() {
closureAddend = closureAddend + 5;
});
console.log("The variable in our main lexical scope after the method
is executed " + closureAddend);
}
> scopeOne()
=> ReferenceError: closureAddend is not defined
The ability to maintain references to the lexical scope at the time of definition is especially useful in callbacks. This is used extensively in JavaScript. It’s common to provide an asynchronous action with a callback to be executed upon completion. The lexical scope that this callback is executed in is often the framework’s we’re using.
What’s next
If you found this useful, you might also enjoy: