Best way to Immediately Invoked Function Expression (IIFE) in perl?

Viewed 311

Borrowing the the term form a Javascript, what is the 'best practice' way to IIFE in perl?

My test code below is a simple loop calling anonymous sub and executing it right away to build an array of subs (which just return the loop index). It is mostly what I want, however I'm needing to use an intermediate variable ( instead of using @_, which changes on the internal function).

use warnings;
use strict;
my @funcs;
for(my $i=0;$i<3;$i++) {
    sub  {
        my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}

for (@funcs) {
    print &$_()."\n";
}
#Output
0
1
2

I know I can use map to restructure this problem. But putting that aside, is there a better way to do this?

Update

Thanks to @ikegami for highlighting some important points.

Just for future views of this question, my thoughts on this:

The 'iterator' for loop has different scoping (is it a map?) than a 'c style' for loop. That cleans up the code with out needing an IIFE at all. Sweet.

Update 2

Following code shows the differences I'm seeing. Not saying one is better than the other but good to know I think. The output I'm after is 0 1 2 but the first one only repeats the last value of $i (3 after the ++ operator).

use warnings;
use strict;
my @funcs;
print "C loop direct assignment of sub\n";
for(my $i=0;$i<3;$i++) {
    $funcs[$i]= sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop direct assignment of sub with variable\n";
for(my $i=0;$i<3;$i++) {
    my $index=$i; #assignment/copy
    $funcs[$index]= sub {$index};
}
print &$_()."\n" for @funcs;

print "For loop interator\n";
@funcs=[];
for my $i (0..2) {
    $funcs[$i]=sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop with IIFE assignment\n";
@funcs=[];
for (my $i=0;$i<3;$i++) {
    sub  {
    my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}
print &$_()."\n" for @funcs;

Out is:

C loop direct assignment of sub                                                                                                                                          
3                                                                                                                                                                        
3                                                                                                                                                                        
3         
C loop direct assignment of sub with variable                                                                                                                            
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                            
For loop interator                                                                                                                                                       
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                        
C loop with IIFE assignment                                                                                                                                                           
0                                                                                                                                                                        
1                                                                                                                                                                        
2        
1 Answers

The Perl equivalent of

(function () {
   var x = ...;
   ...
})();

is

sub {
   my $x = ...;
   ...
}->();

That said, the IIFE is just a workaround that's simply not needed in Perl.

(function () {
   var x = ...;
   ...
})();

is a workaround for

{
   my $x = ...;
   ...
}

and

var result = (function () {
   return ...;
})();

is a workaround for

my $result = do {
   ...
};

It looks like you are trying to translate something similar to the following:

let funcs = [];
for (let i=0; i<3; ++i) {
   (function() {
      var index = i;
      funcs.push( function() { return index; } );
   })();
}

for (let func of funcs)
   console.log(func());

The following is the direct translation:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   sub {
      my $index = $i;
      push @funcs, sub { $index };
   }->();
}

say $_->() for @funcs;

But there's simply no point in using an IIFE. One would simply use the following:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   my $index = $i;
   push @funcs, sub { $index };
}

say $_->() for @funcs;

Now, one tends to avoid C-style for loops in Perl because using foreach loops are far more readable (and more efficient!). It also makes the solution even simpler because the loop variable of a foreach loop is scoped to the body of the loop rather than scoped to the loop statement.

my @funcs;
for my $i (0..2) {
   push @funcs, sub { $i };
}

say $_->() for @funcs;
Related