Altering values by reference

G

Gunnar Hjalmarsson

Dela said:
Is there a way of altering a variable sent as a reference to a
subroutine in Perl *without* using a return value?

Suppose I had a sub doSomething which added 10 to a value. Assuming
I sent it by reference, it could like something like this:

sub doSomething
{
my $reference = shift;
my $value = $$reference;
return ($value + 10);
}

And it would be called:
my $x = 1;
my $y = doSomething(\$x);

No problem. But is there a way I could call the sub such that the
value of $x could be altered in situ without returning a value,
even over different packages? Something like:

my $x = 1;
myOtherPackage::doSomething(\$x); #such that $x now equals 11

sub doSomething { ${$_[0]} += 10 }

/ Gunnar
 
M

Malte Ubl

Dela said:
Dear All,

I was having a discussion with a die-hard Pascal programmer yesterday, and a
point was raised I couldn't answer, and I said I would try and find the
answer for him. Is there a way of altering a variable sent as a reference
to a subroutine in Perl *without* using a return value? As I recall, in
Pascal, you send to a function using either the value or declaring it as
var, in which case in can get altered in the procedure:

procedure myProc(x : Integer; var y : Integer)

Whatever is sent to the procedure as x remains unchanged, but anything which
happens to y (because of the var keyword) is changed in the original
variable. I think (sorry of the syntax for Pascal is off, but it has been a
long time.) Is such a thing possible in Perl?

Parameters in Perl are always passed by reference (That is, the
references reside inside the magical array @_). "Pass by value" only
happens when you take things out of @_ (e.g. by calling shift without
arguments). If you access @_ directly you get the desired behavior.

some code: (untested)

sub inc {
$_[0]++
}

my $i = 0;

inc($i);

print $i

shows that $i has been modified inside the subroutine inc.

bye
malte
 
D

Dela Lovecraft

Dear All,

I was having a discussion with a die-hard Pascal programmer yesterday, and a
point was raised I couldn't answer, and I said I would try and find the
answer for him. Is there a way of altering a variable sent as a reference
to a subroutine in Perl *without* using a return value? As I recall, in
Pascal, you send to a function using either the value or declaring it as
var, in which case in can get altered in the procedure:

procedure myProc(x : Integer; var y : Integer)

Whatever is sent to the procedure as x remains unchanged, but anything which
happens to y (because of the var keyword) is changed in the original
variable. I think (sorry of the syntax for Pascal is off, but it has been a
long time.) Is such a thing possible in Perl?

Suppose I had a sub doSomething which added 10 to a value. Assuming I sent
it by reference, it could like something like this:

sub doSomething
{
my $reference = shift;
my $value = $$reference;
return ($value + 10);
}

And it would be called:
my $x = 1;
my $y = doSomething(\$x);

No problem. But is there a way I could call the sub such that the value of
$x could be altered in situ without returning a value, even over different
packages? Something like:

my $x = 1;
myOtherPackage::doSomething(\$x); #such that $x now equals 11


Any help would be really appreciated.


Dela
 
B

Brian McCauley

Dela Lovecraft said:
sub doSomething
{
my $reference = shift;
my $value = $$reference;
return ($value + 10);
}

And it would be called:
my $x = 1;
my $y = doSomething(\$x);

No problem. But is there a way I could call the sub such that the value of
$x could be altered in situ without returning a value, even over different
packages?

packages are irrelevant unless you are using _symbolic_ references.

Something like:
my $x = 1;
myOtherPackage::doSomething(\$x); #such that $x now equals 11

No problem

package myOtherPackage;
sub doSomething
{
my $reference = shift;
$$reference += 10;
}

I you dont like putting the \ in the call to doSomething() you can put
it in a prototype instead. Or you can manipulate $_[0] directly rather
than using shift.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
T

Tad McClellan

Dela Lovecraft said:
Is there a way of altering a variable sent as a reference
to a subroutine in Perl *without* using a return value?


Yes.

In fact, you can alter a variable even if it is NOT a reference.

(as long as it IS an "lvalue".)


[snip: call-by-value vs. call-by-reference]

Is such a thing possible in Perl?

Yes.


Suppose I had a sub


Then you would surely read the docs for subroutines (perlsub.pod)
and come across this:

Because the assignment copies the values, this also has the effect
of turning call-by-reference into call-by-value. Otherwise a
function is free to do in-place modifications of C<@_> and change
its caller's values.

and you would have already known the answer to your question. :)



To get call-by-reference (the default) in Perl:

by_ref($x);
sub by_ref { $_[0] += 10 }

To get (the effect of) call-by-value in Perl:

by_val($x);
sub by_val { my $num = $_[0]; $num += 10 } # make copy, operate on copy


Neither of them use what is termed a "reference" in Perl (ie. perlref.pod).
 
T

Thens

Dela Lovecraft wrote:

Parameters in Perl are always passed by reference (That is, the
references reside inside the magical array @_). "Pass by value" only
happens when you take things out of @_ (e.g. by calling shift without
arguments). If you access @_ directly you get the desired behavior.

Now i have another question are both these same

sub doSomething{
my ($arg1, $arg2) = @_;
..
}

sub doSomething{
my $arg1 = shift;
my $arg2 = shift;
..
}


Since you (and perldoc perlsub) say that the @_ contains aliases to scalar parameters and when you shift it they become values. Iam slightly confused. Im my first assignment am I assigning the references then ? I have code like these that has been working properly.

Thanks in advance

Regards,
Thens
 
D

Dela Lovecraft

To al that answered.

Thanks very much. I knew it was possible somehow, but I couldn't quite get
my head round it. I don't do a vast amount of coding, so was a bit lost.

Thanks again,


Dela
 
T

Tad McClellan

Thens said:
are both these same

sub doSomething{
my ($arg1, $arg2) = @_;
..
}

sub doSomething{
my $arg1 = shift;
my $arg2 = shift;
..
}


Yes, with regard to call-by-value vs. call-by-reference.

No, with respect to their effects on the contents of @_.
 
B

Bart Lateur

Dela said:
Is there a way of altering a variable sent as a reference
to a subroutine in Perl *without* using a return value?

Yes. The values in @_° are aliases to the original values. So modify
$_[0] directly, and you'll modify the first parameter; etc.

For example:

sub inc {
$_[0]++;
}

my $x = 3;
inc $x;
print $x; # prints "4"

It's only when assigning the contents out of @_ to your local (usually
lexical) variables, that you actually make a copy.

sub foo {
my $x = shift; # copy
my($y, $z) = @_; # copy
$x++; $y++; $z++;
# The original parameters are still unaltered
}
 
B

Brian McCauley

Thens said:
sub doSomething{
my ($arg1, $arg2) = @_;
..
}

sub doSomething{
my $arg1 = shift;
my $arg2 = shift;
..
}
Since you (and perldoc perlsub) say that the @_ contains aliases
to scalar parameters and when you shift it they become values.

No, they remain aliases (lvalues) even when you shift. It is when you
evaluate then in an rvalue context (i.e. a context like that found on
RHS of an assignment) they become (r)values.

sub one {
# Due to a mis-feature of the Perl compiler this genreates spurious
# compile-time error:
# Can't modify shift in postincrement (++)
# If I try to do:
# shift()++;
# Actually you can, but you have to fool the compiler in to not noticing.
$_++ for shift;
}

sub two {
$_[0]++;
}

my $q = 1;
one($q);
print "After one(): $q\n";
two($q);
print "After two(): $q\n";
__END__
After one(): 2
After two(): 3

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 

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
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top