1

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?

asked Jan 20, 2016 at 3:38
6
  • 1
    What do you mean by # Fails because list has an undefined method on the second iteration of the loop? Commented Jan 20, 2016 at 3:41
  • Sorry, I had left my code incomplete. I am in fact calling another function within the loop. So I believe once it calls that function it resets list to nil. I used a begin and rescue block and that is to me what appears to be happening. Commented Jan 20, 2016 at 3:44
  • Show the actual code then. Commented Jan 20, 2016 at 3:45
  • I don't see any issue with the code list = [ 1, 2, 3 ]; list.each { |item| print item } Commented Jan 20, 2016 at 3:48
  • Weird. Totally lost on this one Commented Jan 20, 2016 at 3:51

3 Answers 3

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"
answered Jan 20, 2016 at 4:14
Sign up to request clarification or add additional context in comments.

Comments

3

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.

answered Jan 20, 2016 at 20:18

Comments

0

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"
answered Jan 20, 2016 at 4:21

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.