Pass by reference question

G

grocery_stocker

If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );


sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}


Wouldn't it be more accurate to say that perl passes the reference by
value? I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.
 
G

grocery_stocker

Yes. So why did you say it passes by reference, when you already know a
more accurate way of saying it?

Because too my knowledge, ALL the perldocs and perl books say perl
just passes the reference. I couldn't find anything in the perldocs
that would hint that perl uses 'pass the reference by value'.
 
J

Jens Thoms Toerring

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it.

No, you can't. Perl only allows to pass scalars to functions and
those are passed by value. The only thing that's a bit special
in Perl is that if you e.g. have an argument that is an array it
automatically gets converted into a list of scalars and the values
of these scalars get passed to the subroutine. (Other languages
have similar ways that may look strange at a first glance, e.g.
in C and C++ if you use an array as the argument of a function
it automatically gets converted into a pointer to the first
element of the array and this value is passed to the function.)
Like for example
@tailings = popmany ( \@a, \@b, \@c, \@d );

Sorry, but here you pass scalars to Perl whose values are
references. This is not the same as "passing by reference".
"Passing by reference" means that an argument automatically
gets converted to a reference and that within the subroutine
receiving it in all places the argument is also automatically
dereferenced without you having to spell it out explicitely.

Compare the these two C++ functions: that do the same thing:

void foo_by_val( int* i ) {
*i = 3;
}

void foo_by_ref( int& i ) {
i = 3;
}

The first one you would have to call as

int x;
foo_by_val( &x );

and the second as

foo_by_ref( x );

Perl only has an equivalent for the foo_by_val() function but
not for foo_by_val().
sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}
Wouldn't it be more accurate to say that perl passes the reference by
value?

It's redundant since Perl only passes by value. A reference is
nothing than a scalar (basically what you would call a pointer
in C or C++) and scalars, the only things you can pass to sub-
routines, are always passed by values.
I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.

You have to because Perl (like e.g. C but unlike Java or C++)
simply doesn't do "pass by reference", just "pass by value".

Regards, Jens
 
J

Josef Moellers

Jens said:
No, you can't. Perl only allows to pass scalars to functions and
those are passed by value.

Why, then, does the following script print "Bar"?

sub f($) {
$_[0] = 'Bar';
}
my $v = 'Foo';
f($v);
print "$v\n";

Josef
 
J

Josef Moellers

Jens said:
No, you can't. Perl only allows to pass scalars to functions and
those are passed by value.

Why, then, does the following script print "Bar"?

sub f($) {
$_[0] = 'Bar';
}
my $v = 'Foo';
f($v);
print "$v\n";

And what does this script's error message tell us?

sub f($) {
$_[0] = 'Bar';
}
f('Foo');

With all due respect,

Josef
 
A

anno4000

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );


sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}


Wouldn't it be more accurate to say that perl passes the reference by
value? I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.

The perceived problem here is mostly due to ambiguous terminology.

There is the common distinction of parameter passing "by value" vs "by
reference". The first one means that all a subroutine ever gets to see
is a copy of the parameter value whereas the second means the subroutine
has access to the variable as it exists in the caller's context and can,
for instance, change the value so that the change is visible to the
caller.

Perl subs implement "pass by reference" in this sense, since assigning
to elements of @_ changes the value for the caller. This description
went into the Perl documentation, and when Perl was young (before Perl
5) this caused no problems because the term "reference" didn't have
a Perl-specific meaning back then.

That changed when Perl 5 introduced its own references (what you get
by prefixing a variable with a backslash). These references are *not*
what Perl uses to implement its "pass by reference", but an entirely
distinct notion. In Perl terms, what is commonly called "pass by
reference" might be called "pass by alias(ing)", but that term is not
in general use and wouldn't be readily understood. So the documentation
continues to use the commonly recognized term even after it has become
ambiguous.

Anno
 
J

Josef Moellers

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );


sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}


Wouldn't it be more accurate to say that perl passes the reference by
value? I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.

Perl passes variables by reference and dereferences them automagically.
If you explicitly pass a reference ('\@a'), you'll have to dereference
it explicitly.
I.e. in your example, popmany is passed four references to references to
arrays.

Josef
 
J

Jens Thoms Toerring

Why, then, does the following script print "Bar"?
sub f($) {
$_[0] = 'Bar';
}
my $v = 'Foo';
f($v);
print "$v\n";
And what does this script's error message tell us?
sub f($) {
$_[0] = 'Bar';
}
f('Foo');

It tells me that I obviously I was writing BS, at least when I
didn't mention that using prototypes changes the picture.

Ok, to the OP: you could write your function e.g. as

sub popmany(\@;\@;\@;\@) {
return map { pop @$_ } @_;
}

and then call it as

@tailings = popmany @a, @b, @c, @d;

using the possibility to "pass by reference" when using prototypes.
But please note that this only will work with up to four arrays,
so the function would be better named pop_up_to_four() or something
like that.

But my personal preference is to avoid prototypes except for the
very purpose they were introduced for, mimiking the behaviour of
built-in functions like push or pop. You still have to use the
dereference syntax for arrays and hashes within the subroutine
since what arrives within the subroutine are still scalars. And
be wary of modifying elements of @_ unless you understand fully
what to expect (I find it a bit weird). And, finally, prototypes
don't influence method calls, only "normal" functions.

At least don't assume that prototypes play a similar role to
those in other languages like C, C++, Java etc., they don't.
They aren't meant for compile time type checking.

Regards, Jens
 
A

anno4000

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );


sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}

On an unrelated note (unrelated to the question, that is), popmany()
can be written more compact as

sub popmany { map pop @$_, @_ }

Anno
 
X

xhoster

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );

You are sticking the backwhacks in front of those arrays, not Perl.
(If you are using prototypes, then perl will in effect add the backwhacks
for you, but that is a different matter).

Since you took the reference, not Perl, then you have to do the
dereference.


sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}

Wouldn't it be more accurate to say that perl passes the reference by
value? I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.

Perl does "pass the thingamabob by alias". That that thingamabob which was
passed by alias is a reference is due to your particulars and Perl's
generals.

Xho
 
X

xhoster

grocery_stocker said:
If perl can pass stuff by reference, then why do you have to deference
it. Like for example

@tailings = popmany ( \@a, \@b, \@c, \@d );

You are sticking the backwhacks in front of those arrays, not Perl.
(If you are using prototypes, then perl will in effect add the backwhacks
for you, but that is a different matter).

Since you took the reference, not Perl, then you have to do the
dereference.
sub popmany {
my $aref;
my @retlist = ();
foreach $aref ( @_ ) {
push @retlist, pop @$aref;
}
return @retlist;
}

Wouldn't it be more accurate to say that perl passes the reference by
value? I just find this sort of odd because in both Java (withc uses
pass the reference by value) and C++ (which supports pass by
reference), I never recall having to dereference a reference like what
I have to in perl.

Perl does "pass the thingamabob by alias". That that thingamabob which was
passed by alias is a reference is due to your particulars and not Perl's
generals.

Xho
 
G

grocery_stocker

You are sticking the backwhacks in front of those arrays, not Perl.
(If you are using prototypes, then perl will in effect add the backwhacks
for you, but that is a different matter).

Let me get this straight. If I use prototypes, perl will in effect add
backwhacks?! I'm starting to get these really horrible images of some
of the AOL engineers using prototypes in Perl scripts and me wondering
why they were sometimes anal retentive about this. Would you or
someone else care to give me an example of this?



Chad
 
P

Paul Lalli

Let me get this straight. If I use prototypes, perl will in effect
add backwhacks?!

Yes. Don't use prototypes. Ever.
Would you or someone else care to give me an example of this?

$ perl -MData::Dumper -e'
sub foo(\@\@) {
print Dumper(@_);
}

my @one = (1, 2, 3);
my @two = (4, 5, 6);
foo(@one, @two);
'
$VAR1 = [
1,
2,
3
];
$VAR2 = [
4,
5,
6
];

Compare and contrast with not using a prototype, in which all of @one
and @two are "flattened" into one big list:

$ perl -MData::Dumper -e'
sub foo {
print Dumper(@_);
}

my @one = (1, 2, 3);
my @two = (4, 5, 6);
foo(@one, @two);
'
$VAR1 = 1;
$VAR2 = 2;
$VAR3 = 3;
$VAR4 = 4;
$VAR5 = 5;
$VAR6 = 6;


Paul Lalli
 
T

Tad McClellan

grocery_stocker said:
Let me get this straight. If I use prototypes, perl will in effect add
backwhacks?!
Would you or
someone else care to give me an example of this?


In addition to all of the ones in the "Prototypes" section in perlsub?

OK.


-----------------------------
#!/usr/bin/perl
use warnings;
use strict;

sub mypush (\@@) {
my($aref, @list) = @_;
foreach ( @list ) {
$aref->[ @$aref ] = $_;
}
}

my @array = qw/zero one two/;
print "before: @array\n";

mypush @array, 'three', 'four'; # look Ma! No backslash!
print "after: @array\n"; # see if @array got modified
 
X

xhoster

grocery_stocker said:
Let me get this straight. If I use prototypes, perl will in effect add
backwhacks?!

If the contents of the prototype dictate it, yes.

I'm starting to get these really horrible images of some
of the AOL engineers using prototypes in Perl scripts and me wondering
why they were sometimes anal retentive about this. Would you or
someone else care to give me an example of this?

$ perl -le 'my @x=1..10; foo(@x); sub foo(\@) {print "@_"}; foo(@x)'
main::foo() called too early to check prototype at -e line 1.
1 2 3 4 5 6 7 8 9 10
ARRAY(0x6227e0)

foo(@x) looks like it should send @x as a list, which is what it does
initially (but with the warning), but because of the prototype in effect
the second time the foo-call is compiled, that time it instead sends the
arrayref.

Xho
 
P

Peter J. Holzer

Why, then, does the following script print "Bar"?
sub f($) {
$_[0] = 'Bar';
}
my $v = 'Foo';
f($v);
print "$v\n";
[...]
It tells me that I obviously I was writing BS, at least when I
didn't mention that using prototypes changes the picture.

No, prototypes have nothing to do with it. If you omit the "($)", the
program behaves exactly the same. Perl always passes parameters by
reference, that is, the elements of @_ are *aliases* of the arguments,
not *copies*. Thus, when you modify a member of @_, you modify the
arguments in the caller.

The usual construct

sub foo {
my ($bar, $baz) = @_;
...
}

simulates passing by value by explicitely making a copy of the
parameters. Now you can modify $bar and $baz to your heart's content
without worrying about changing the arguments in the caller.

hp
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top