I am doing pass-by-reference like this:
use strict;
use warnings;
sub repl {
local *line = \$_[0]; our $line;
$line = "new value";
}
sub doRepl {
my ($replFunc) = @_;
my $foo = "old value";
$replFunc->($foo);
print $foo; # prints "new value";
}
doRepl(\&repl);
Is there a cleaner way of doing it?
Prototypes don't work because I'm using a function reference (trust me that there's a good reason for using a function reference).
I also don't want to use $_[0]
everywhere in repl
because it's ugly.
Have you looked at Data::Alias? It lets you create lexically-scoped aliases with a clean syntax.
You can use it to create pass-by-reference semantics like this:
use strict;
use warnings;
use Data::Alias;
sub foo {
alias my ($arg) = @_;
$arg++;
}
my $count = 0;
foo($count);
print "$count\n";
The output is 1
, indicating that the call to foo
modified its argument.
sub repl {
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
}
There are a couple of ways to do this. Explicitly pass a scalar ref to $foo
, or take advantage of Perl's built-in pass by reference semantics.
Explicit reference:
my $foo = "old value";
doRepl( \&repl, \$foo );
print $foo; # prints "new value";
sub repl {
my $line = shift;
$$line = "new value";
}
sub doRepl {
my ($replFunc, $foo) = @_;
$replFunc->($foo);
}
Pass by reference:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
$replFunc->(@_);
}
Even fancier pass by reference:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
&$replFunc;
}
The first one use normal perl hard references to do the job.
The first pass by ref method uses the fact that Perl passes arguments to all functions as references. The elements of @_
are actually aliases to the values in the argument list when the subroutine is called. By altering $_[0]
in foo()
, you actually alter the first argument to foo()
.
The second pass by ref method use the fact that a sub called with an &
sigil and no parens gets the @_
array of its caller. Otherwise it is identical.
Update: I just noticed you desire to avoid $_[0]
. You can do this in repl if you want:
sub repl {
for my $line( $_[0] ) {
$line = 'new value';
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With