I find it difficult to program without using closures in the following pattern:
function outerFunction(input) {
var closureVar = "I'm here with ";
function innerFunction() {
return closureVar + input;
}
return innerFunction();
}
outerFunction('outer input'); // I'm here with outer input
This makes sense to me. The outerFunction defines an environment that innerFunction has reference to upon invocation.
I would like to see how Ruby accomplishes the same thing. I understand Ruby uses blocks, procs and lambas, but I cannot seem to achieve the same lexical scoping as I can with JavaScript.
Ruby naive attempt:
def outer_function
list = [ 1, 2, 3 ]
list.each { |item| print item }
end
# Fails because list has an undefined method on the second iteration of the loop
another attempt
def outer_function
list = Proc.new { return [ 1, 2, 3 ] }
list.call.each { |item| another_function item }
end
def another_function item
puts item
end
# Same problem
So, how can I achieve this pattern in Ruby?
3 Answers 3
While Javascript has one type of lambda construct (an anonymous function), Ruby has several. The most common are blocks (passed to methods as in each in your example), Procs (which are like blocks that are bound to a execution context which they retain even when passed around), and Lambdas which are probably closest to anonymous functions. I won't go into the details of Procs vs Lambdas here.
Here are examples of these constructs in Ruby:
# Using a block + yield
def my_method(arg)
puts arg + yield(3)
end
my_method(5) { |arg| arg * 2 }
# => 11
# Binding the block to a Proc then using #call
def print(&block)
puts block.call
end
# Creating a Proc that can be passed around and then #called
def other_method(arg, other_args*)
arg.call(other_args*)
end
var = 3
prc = Proc.new { puts var }
other_method(prc)
# Creating a Lambda using stabby syntax
num = 3
l = -> (arg) { arg + 2 + num }
other_method(l, 1)
In Ruby you could write your JS example as:
def outer(input)
closure_var = "I'm here with "
inner = -> { closure_var + input }
inner.call
end
outer('outer input')
In IRB:
jbodah@Joshs-MacBook-Pro-2 2.1.3p242 ~ (none) $ irb
irb(main):001:0> def outer(input)
irb(main):002:1> closure_var = "I'm here with "
irb(main):003:1>
irb(main):004:1* inner = -> { closure_var + input }
irb(main):005:1>
irb(main):006:1* inner.call
irb(main):007:1> end
=> :outer
irb(main):008:0>
irb(main):009:0* outer('outer input')
=> "I'm here with outer input"
Comments
function outerFunction(input) {
var closureVar = "I'm here with ";
function innerFunction() {
return closureVar + input;
}
return innerFunction();
}
console.log(outerFunction('outer input')); // I'm here with outer input
Let's first re-write your ECMAScript to use function expressions:
const outerFunction = function (input) {
const closureVar = "I'm here with ";
const innerFunction = function () {
return closureVar + input;
}
return innerFunction();
}
console.log(outerFunction('outer input')); // I'm here with outer input
Now let's re-write that into more modern style:
const outerFunction = input => {
const closureVar = "I'm here with ";
const innerFunction = () => closureVar + input;
return innerFunction();
};
console.log(outerFunction('outer input')); // I'm here with outer input
Now, it's actually fairly simple to translate this to Ruby:
outer_function = -> input {
closure_var = "I'm here with "
inner_function = -> { closure_var + input }
inner_function.()
}
puts outer_function.('outer input') # I'm here with outer input
As you can see, the translation is actually pretty straightforward and the semantics are similar. It is, however, not very idiomatic Ruby. In general, objects and methods are preferred over closures for encapsulating state, but sometimes, closures are useful and used.
A more idiomatic style might be something like this:
def outer_method(input)
closure_var = "I'm here with "
inner_function = -> { closure_var + input }
inner_function.()
end
puts outer_method('outer input') # I'm here with outer input
But for such a small toy example it's hard to say and hard to demonstrate what idiomatic Ruby would look like.
If you are interested in stuff like this, you might want to look through a toy project of mine, where I show how to implement linked lists using nothing but closures in a variety of languages including Clojure and various other Lisps, Smalltalk and some of its descendants, ECMAScript and CoffeeScript, Ruby, Python, PHP, Perl, etc. Note that the code looks very similar in most languages, but note also that the code is very un-idiomatic in almost all of the languages, except Scheme and maybe Clojure. It isn't even idiomatic CommonLisp as far as I can tell.
The Ruby code you posted in the second half of your question is completely unrelated to either the code or the concepts in the first half of your question: there are no closures, no issues of lexical scoping, and there is no need to use them.
In fact, the first snippet you posted just works as-is:
def outer_function
list = [ 1, 2, 3 ]
list.each { |item| print item }
end
outer_function
# 123
The second just has a tiny problem:
def outer_function
list = Proc.new { return [ 1, 2, 3 ] }
# The call to `each` is dead code since the call to `list.call` will already return
list.call.each { |item| another_function item }
end
# This method never gets called
def another_function item
puts item
end
outer_function
# => [1, 2, 3]
return is used to return a value from a method. So, what method does the return return from? Well, it returns from outer_function, since that's the only method there! list is a Proc, not a method. To return from a Proc, you use the next keyword instead:
def outer_function
list = Proc.new { next [ 1, 2, 3 ] }
list.call.each { |item| another_function item }
end
def another_function item
puts item
end
outer_function
# 1
# 2
# 3
Alternatively, you could leave out the next altogether, since the last expression evaluated inside a compound expression (a block, a method, a class, whatever) is its return value anyway:
def outer_function
list = Proc.new { [ 1, 2, 3 ] }
list.call.each { |item| another_function item }
end
def another_function item
puts item
end
outer_function
# 1
# 2
# 3
Or, you could replace the Proc with a lambda (which is actually also a Proc but with slightly different semantics):
def outer_function
list = -> { return [ 1, 2, 3 ] }
list.call.each { |item| another_function item }
end
def another_function item
puts item
end
outer_function
# 1
# 2
# 3
There are two semantic differences between Procs (created by Proc.new or Kernel#proc) and lambdas (created by Kernel#lambda or the stabby lambda literal -> (params) { code }): return in a Proc returns from the lexically enclosing method (just like in a block) whereas return in a lambda returns from the lambda itself (just like in a method), and the argument binding semantics of Procs are the same as those of blocks, whereas the argument binding semantics of lambdas are the same as those of methods.
To recap: there are two differences, return and argument binding. And in both cases, Proc behaves like a block and lambda behaves like a method. Mnemonic: Proc rhymes with "block", and "lambda" and "method" are both Greek.
Comments
The below will do it for you , just be mindful inner_function is not really a method.Hence it is a lambda which behaves like a method. read more here LINK .
def outer_function(item)
outer_variable = "input"
inner_function = lambda { puts item puts outer_variable }
inner_function[]
end
outer_function "I'm here with " # prints "I'm here with input"
list = [ 1, 2, 3 ]; list.each { |item| print item }