"local @_ = @_;" for "pass-by-value"?

M

Mihail

Hello,

again about sub{} behavior and "pass-by-call"/"pass-by-value".
Is it clean and recommended to use local @_ ?

sub {
local @_ = @_;
....
}

I do not like the way of fantasy arrays:

sub {
my @pass_by_value_workaround = @_;
....
}

It is ugly. But i still don't see clear advice how to do
"call-by-value"? And "local" things seems to change from
version to version.

Thank you.

Mihail
 
B

Brian McCauley

Mihail said:
Hello,

again about sub{} behavior and "pass-by-call"/"pass-by-value".
Is it clean and recommended to use local @_ ?

sub {
local @_ = @_;
...
}

The local() here serves no useful purpose - you may as well write

sub {
@_ = @_;
...
}

Replacing elements in @_ (by splice() or wholesale assignments) does
not alter the parameters passed to the subroutine.
I do not like the way of fantasy arrays:

sub {
my @pass_by_value_workaround = @_;
...
}

It is ugly.

Perhaps you should show us a real example of a subroutine where that is
more ugly than the alternative.
 
M

Mihail

sub {
The local() here serves no useful purpose - you may as well write

sub {
@_ = @_;

It is not true. "local @_ = @_" preserve argument from being changed
by function.
Perhaps you should show us a real example of a subroutine where that is
more ugly than the alternative.

I don't like it because it is one varible too much. I don't want new
varible - i want the old one not to overwritten. And with
"local @_ = @_" i can correct previously wrotten with error
("pass-by-value" is default).

Here is simple example where it works:

#!/usr/bin/perl
use strict;
use warnings;
my $result1 = 0;
my $result2 = 0;
for (1..999) {
my $i = $_;
$result1 = $result1 + func1($i);
$result2 = $result2 + func2($i);
}
print "*** Sum of first sums of digits : $result1\n";
print "*** Sum of last sums of digits : $result2\n";
sub func1 {

# here is it.
local @_ = @_;
my $sum = 0;
do {
$_[0] =~ m/^(.).?/;
$sum = $sum + $1;
$_[0] =~ s/^.//;
} while ($_[0]);
return $sum;
}
sub func2 {
return $_[0] % 9 if (($_[0] % 9) > 0);
return 9;
}
 
M

Mihail

Mihail said:
It is not true. "local @_ = @_" preserve argument from being changed
by function.

O.K. "@_ = @_" seems to do the same job as "local @_ = @_". But
i still prefer local, "@_ = @_" looks even more crazy and "my @qqq = @_"
is not readable as command "let me been pass-by-value".

Thank you very much.
 
G

Gunnar Hjalmarsson

Abigail said:
Mihail wrote:
@@ again about sub{} behavior and "pass-by-call"/"pass-by-value".
@@ Is it clean and recommended to use local @_ ?
@@
@@ sub {
@@ local @_ = @_;
@@ ...
@@ }
@@
@@ I do not like the way of fantasy arrays:
@@
@@ sub {
@@ my @pass_by_value_workaround = @_;
@@ ...
@@ }
@@
@@ It is ugly. But i still don't see clear advice how to do
@@ "call-by-value"? And "local" things seems to change from
@@ version to version.

I would use

my @arg = @_;

myself, but if you like 'local @_', I don't have any problems with it.
Not that me having problems with it is important - it's your code, if
you are comfortable with it, use it.

To me, doing so (or doing '@_ = @_;', which serves the same purpuse) is
obfuscation.

When I see a line such as

$_[0] *= 8;

I'm automatically assuming that the passed-in variable gets changed. If
somebody else but the OP would later read or maintain the code,
explicitly assigning to @_ might cause confusion.
 
A

Anno Siegel

Mihail said:
O.K. "@_ = @_" seems to do the same job as "local @_ = @_". But
i still prefer local, "@_ = @_" looks even more crazy and "my @qqq = @_"
is not readable as command "let me been pass-by-value".

Most of the time the point is moot anyway, since most Perl subs use
named parameters

sub foo {
my( $this, $that, @array) = @_;

and forget about @_. Even if the arguments represent one array with
anonymous elements, there is usually a descriptive name for that which
makes the "my @frobnitzers = @_" notation natural.

With very short (one-line) subs it is common to access $_[ 0] and $_[ 1]
(rarely more) directly, but then the simplicity makes it easy to make sure
no values are changed.

That is the standard way of dealing with the call-by-reference issue, and
it is usually sufficient.

Anno
 
A

Anno Siegel

Gunnar Hjalmarsson said:
To me, doing so (or doing '@_ = @_;', which serves the same purpuse) is
obfuscation.

It is a line of code that needs a comment, either way. In my world that
counts against using it.
When I see a line such as

$_[0] *= 8;

I'm automatically assuming that the passed-in variable gets changed. If
somebody else but the OP would later read or maintain the code,
explicitly assigning to @_ might cause confusion.

Well, since the purpose of the action is emulating call-by-value, that
kind of code will probably not happen. I think the purpose is to protect
against hidden changes to arguments, as in

for my $thing ( @_ ) {
# ...
$thing *= 8;
# ...
}

where the programmer doesn't intend the change.

Like you, I prefer the standard method of using named lexical arguments,
even for a single array argument. Then *only* use @_ directly when you
need to, for assignment or other purposes. It doesn't make argument
changes impossible, but they will stand out, which is usually good enough.

Anno
 
M

Mihail

I would use
Like you, I prefer the standard method of using named lexical arguments,
even for a single array argument. Then *only* use @_ directly when you
need to, for assignment or other purposes. It doesn't make argument
changes impossible, but they will stand out, which is usually good enough.


Yes, but the way it ("pass-by-value") is done is very different.

"A "local" just gives temporary values to global (meaning
package) variables. It does not create a local variable. This is
known as dynamic scoping. Lexical scoping is done with "my", which
works more like C's auto declarations."

What is faster?

Mihail
 
A

Anno Siegel

Mihail said:
Yes, but the way it ("pass-by-value") is done is very different.

Sure, but the actual behavior is very similar (though not identical).
"A "local" just gives temporary values to global (meaning
package) variables. It does not create a local variable. This is
known as dynamic scoping. Lexical scoping is done with "my", which
works more like C's auto declarations."

What is faster?

Faster??? If you have to worry about the speed of parameter passing,
Perl is not your language, at least not for that part of the program.

I'd expect lexical varable(s) to be slightly faster, but that's beside the
point. The point is readability, and named lexical parameters enhance
readability while "@_ = @_" (with or without "local") obscures it.

However, as Abigail noted, it's your code, and if you really want
physical protection of the arguments, go with "@_ = @_". It works.

Anno
 
G

Gunnar Hjalmarsson

Abigail said:
Gunnar Hjalmarsson wrote:
}} To me, doing so (or doing '@_ = @_;', which serves the same purpuse) is
}} obfuscation.

To me, obfuscation is something that looks to do something different than
it does - or when you use a roundabout way to archieve something.

IMO, '@_ = @_;' is neither. It's a terse way to archieve something, and
it doesn't pretend to do something else.

I could understand a newbie programmer labelling it as "obfuscated", but
I doubt you'd consider yourself a newbie.

Newbie or not, I'm just a Perl hobbyist. :) And, to be honest, before
this thread, no bells would have rung if I had seen the line '@_ = @_;'
without comments in a Perl sub.
}} When I see a line such as
}}
}} $_[0] *= 8;
}}
}} I'm automatically assuming that the passed-in variable gets changed.

That raises a 'red flag' with me. Not about the code, but about the
programmer. Never 'automatically assume'. A lot of programming bugs
are made that way.

Okay, point taken. But no matter how cautious you are, the risk that you
make mistakes is reasonably reduced if the style applied cares about
readability.
 
A

Anno Siegel

Abigail said:
Anno Siegel ([email protected]) wrote on MMMMDII September
MCMXCIII in <URL:))
)) Most of the time the point is moot anyway, since most Perl subs use
)) named parameters

"most Perl subs"? How would you know? Have you checked all of them?

No. Like everybody else I'm going by the unfounded assumption that
the code I happen to come across is representative for the majority
of Perl code.
))
)) sub foo {
)) my( $this, $that, @array) = @_;

Those are not named parameters. Named parameters show up in the *call*
of the function.

Okay... sloppy terminology. What I meant was assignment of the arguments
to named (lexical) variables.
What you have are positional parameters. Of which I
think the overwhelming majority of Perl subs use (but I haven't checked
them all).

Right. And the rest use actual named parameters which also transfers
the values, usually to lexical hashes. Direct access to @_ is rare
in published Perl code, except for one-liners.

Anno
 
A

Anno Siegel

[...]
If I see '@_ = @_;', or '$_ = $_;' the purpose is immediately clear to
me: disabling of the effects of aliasing. And while I seldomly (perhaps
never) use '@_ = @_;', I do use '$_ = $_;', typically inside a map or a
for statement.

I find that occasionally "$_ = $_" gets optimized away in the wrong place.
This bit of code tries to extend a bit vector $vec to at least 10 bytes
without changing its content if it is already that long:

$_ = $_ for vec( $vec, 79, 1);

It does nothing. Changing the assignment to "$_ = $_ + 0" works as
intended. Arguably a bug, but I can't be bothered to report it.

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,503
Latest member
supremedee

Latest Threads

Top