views:

157

answers:

2

How would you take a reference to an array slice such that when you modify elements of the slice reference, the original array is modified?

The following code works due to @_ aliasing magic, but seems like a bit of a hack to me:

my @a = 1 .. 10;
my $b = sub{\@_}->(@a[2..7]);
@$b[0, -1] = qw/ < > /;
print "@a\n";
# 1 2 < 4 5 6 7 > 9 10

Anyone have a better / faster way?

Edit: the code example above is simply to illustrate the relationship required between @a and $b, it in no way reflects the way this functionality will be used in production code.

+4  A: 

Data::Alias seems to be able to do what you want:

#!/usr/bin/perl

use strict; use warnings;

use Data::Alias;

my @x = 1 .. 10;

print "@x\n";

my $y = alias [ @x[2 ..7] ];
@$y[0, -1] = qw/ < > /;

print "@x\n";

Output:

1 2 3 4 5 6 7 8 9 10
1 2 < 4 5 6 7 > 9 10
Sinan Ünür
I am working on a set of functions that add variable step size to existing perl builtin's (think natatime but more perlish).For example: for (every 3 => 1 .. 10) { print "@$_\n" } I need the slice reference passed in as $_ to be an alias to the original values, not a copy. the sub{\@_}->(...) syntax is what i am using now, but like i said, it seems a bit round about.
Eric Strom
interesting module, it will definitely come in handy. this method seems about 50% faster for short lists, the gains drop off as the lists get longer.
Eric Strom
+3  A: 

That's how you do it, yes. Think about it for a bit and it's not such a hack; it is simply using Perl's feature for assembling arbitrary lvalues into an array and then taking a reference to it.

You can even use it to defer creation of hash values:

$ perl -wle'my %foo; my $foo = sub{\@_}->($foo{bar}, $foo{baz}); print "before: ", keys %foo; $foo->[1] = "quux"; print "after: ", keys %foo'
before: 
after: baz
ysth
@ysth => do you know if any of the 'simple' subroutine definitions like sub{@_} or sub{\@_} end up optimizing away all of the call stack manipulation internally?
Eric Strom
no, they don't.
ysth