views:

198

answers:

10

I wonder how the following closure test can be written in other languages, such as C/C++ and Java. Can the same result be expected also in Perl, Python, and PHP?

Ideally, we don't need to make a new local variable such as x and assign it the value of i inside the loop, but just so that i has a new copy in the new scope each time. (if possible). (some discussion is in this question.)

The following is in Ruby, the "1.8.6" on the first line of result is the Ruby version which can be ignored.

p RUBY_VERSION

$foo = []

(1..5).each do |i|
  $foo[i] = lambda { p i }
end

(1..5).each do |j|
  $foo[j].call()
end

the print out is:

[MacBook01:~] $ ruby scope.rb
"1.8.6"
1
2
3
4
5
[MacBook01:~] $ 

Contrast that with another test, with i defined outside:

p RUBY_VERSION

$foo = []

i = 0

(1..5).each do |i|
  $foo[i] = lambda { p i }
end

(1..5).each do |j|
  $foo[j].call()
end

the print out:

[MacBook01:~] $ ruby scope2.rb
"1.8.6"
5
5
5
5
5
[MacBook01:~] $ 
+2  A: 

The upcoming C++0x has lambdas and allows to specify wether the variables are to be captured by value (=) or by reference (&), with which it should look like this:

std::vector<std::function<void ()>> foo;

for(int i=0; i<5; ++i) {
    foo.push_back([=](){ std::cout << i << std::endl; });
}

for(int i=0; i<5; ++i) {
    foo[i]();
}

For the second version:

int i;

for(i=0; i<5; ++i) {
    foo.push_back([&](){ std::cout << i << std::endl; });
}

for(int j=0; j<5; ++j) {
    foo[j]();
}
Georg Fritzsche
What headers do you need to include for this to work? I can't find std::function in GCC 4.4.1.
Joey Adams
`std::function` is in `functional` - at least gcc 4.5 supports it: http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x
Georg Fritzsche
+1  A: 

GNU C (not C++) supports nested functions. However, it only supports downwards funargs. If a variable goes out of scope, it goes out of scope, and a function object referring to it will be invalidated.

The following example prints 5 5 5 5 5 due to lexical scoping; the callbacks are all referring to the same i rather than individual instances:

#include <stdio.h>

int main(void)
{
    int (*callbacks[5])(void);
    int i, j;

    for (i=0; i<5; i++) {
        int callback(void) {
            return i;
        }
        callbacks[i] = callback;
    }

    for (j=0; j<5; j++)
        printf("%d ", callbacks[j]());
    printf("\n");

    return 0;
}

An attempt to rectify this situation would look like this:

#include <stdio.h>

int main(void)
{
    int (*callbacks[5])(void);
    int i, j;

    for (i=0; i<5; i++) {
        int tmp = i;
        int callback(void) {
            return tmp;
        }
        callbacks[i] = callback;
    }

    for (j=0; j<5; j++)
        printf("%d ", callbacks[j]());
    printf("\n");

    return 0;
}

However, tmp goes out of scope every iteration, meaning all the callback objects are invalidated. They would not be if GNU C supported upwards funargs. The above code yields undefined behavior.

Because GNU C supports nested functions and downward funargs, it provides some of the benefits of closures, but not all of them.

Joey Adams
+2  A: 

Because C doesn't support closures, to get something similar you have to explicitly carry around the values or references you want. Like this:

#include <stdio.h>

typedef struct {
    int i;
    void (*f)(int);
} lambda_a;

void lambda_a_call(const lambda_a *l)
{
    l->f(l->i);
}

void func_a(int i)
{
    printf("%d\n", i);
}

int main()
{
    lambda_a foo[5];
    int i, j;

    for (i = 0; i < 5; i++)
    {
        foo[i].i = i;
        foo[i].f = func_a;
    }

    for (j = 0; j < 5; j++)
    {
        lambda_a_call(&foo[j]);
    }

    return 0;
}

Or for your second version:

#include <stdio.h>

typedef struct lambda_b {
    int *i;
    void (*f)(int *);
} lambda_b;

void lambda_b_call(const lambda_b *l)
{
    l->f(l->i);
}

void func_b(int *i)
{
    printf("%d\n", *i);
}

int main()
{
    lambda_b foo[5];
    int i, j;

    for (i = 1; i < 6; i++)
    {
        foo[i].i = &i;
        foo[i].f = func_b;
    }

    for (j = 0; j < 5; j++)
    {
        lambda_b_call(&foo[j]);
    }

    return 0;
}
caf
+2  A: 

In Python you get the second behavior by default:

foo = [] 
for i in range(5): 
  foo.append(lambda: i) 

for j in range(5): 
  print foo[j]() 

This prints 4 4 4 4 4 (everything is 1 less than in your example because this fills the array from index 0). So each closure refers to the (same) outside variable, rather than store its value at the time of closure definition.

To get the first behavior, there is a Python trick of storing the value at the time of definition in the default value of a function parameter:

foo = [] 
for i in range(5): 
  foo.append(lambda x=i: x) 

for j in range(5): 
  print foo[j]()

This prints 0 1 2 3 4. You could've even used lambda i=i: i, but I used x for clarity.

DS
+1  A: 

The Groovy equivalent would be

foo = []

(1..5).each {i ->
  foo[i] = { println i }
}

(1..5).each {j ->
  foo[j].call()
}

but a nicer implementation would be

foo = []

(1..5).each {i ->
  foo << { println i }
}

foo.each {j ->
  j.call()
}

and in both cases the '.call()' could be replaced by '()'

foo = []

(1..5).each {i ->
  foo << { println i }
}

foo.each {j ->
  j()
}

In Java 6 one could write

In Java 6 I would write

Runnable[] foo = new Runnable[6];

for (int i = 1; i <= 5; i++) {
  final int finalI = i;
  foo[i] = new Runnable() {public void run(){System.out.println(finalI);}}
}

for (int j = 1; j <= 5; j++) {
  foo[j].run();
}

which is ugly compared to the groovy code. But Java 7 will have closures, but I have not yet played with that.

Tobias Schulte
A: 

Scala:

println(System getProperty "java.version")

val foo = new collection.mutable.ArrayBuffer[() => Unit]

1 to 5 foreach { i => 
  foo += {() => println(i)}
}

1 to 5 foreach { j => 
  foo(j - 1)()  // (j - 1) because ArrayBuffer is indexed from 0
}

A more Scala-esque (one that doesn't use a mutable data structure) version:

println(System getProperty "java.version")

val foo = 1 to 5 map {i => {() => println(i)}}

foo foreach {_()}
missingfaktor
A: 

Java:

// An interface that wraps a function that takes no arguments
// and returns nothing
interface Action0 {
  public void apply();
}

In the main():

System.out.println(System.getProperty("java.version"));
List<Action0> foo = new ArrayList<Action0>();
for(int i = 1; i <= 5; ++i) {
  final int j = i;
  foo.add(
    new Action0() {
      @Override
      public void apply() {
        System.out.println(j);
      }
    }
  );
}
for(Action0 action : foo) {
  action.apply();
}
missingfaktor
A: 

JavaScript:

var foo = [];

for (var i = 0; i < 5; i++) {
    foo[i] = function() { print (i); }
}

for (var i = 0; i < 5; i++) {
    foo[i].call ();
}

Output:

$ js cl.js 
0
1
2
3
4

N.B. print() function is provided by stand-alone SpiderMonkey interpreter. To execute in browser, replace print() with some alert() or equivalent.

el.pescado
A: 

Perl:

#!/usr/bin/perl

use strict;
use warnings;

my @foo;

for my $i (1..5) {
    $foo[$i] = sub { print "$i\n"; };
}

for my $i (1..5) {
    $foo[$i]();
}

Much like original Ruby sample.

el.pescado
+1  A: 

C♯:

var foo = new List<Action>();
for(var i = 1; i <= 5; ++i) {
  var j = i;
  foo.Add(() => {Console.WriteLine(j);});
}
foo.ForEach(f => f());

Dunno how to get the version number though.

missingfaktor