Get the reference to an array from a function...

H

howa

hi,

consider the program, why reference to an array returning from a
function did not work?


#------------------------------

sub test {

my @arr = ("1", "2", "3");
return @arr;
}

my $size = test();
my @arr = test();

my $arr_ref = \test();

use Data::Dumper;
#print Dumper ( $size );
#print Dumper ( @arr );
print Dumper ( $arr_ref ); # DIDN'T WORK!
 
H

howa

Aukjan van Belkum 寫é“:
howa said:
hi,

consider the program, why reference to an array returning from a
function did not work?


my $arr_ref = \test();

You should change this line to:

my $arr_ref = [ test() ];

This will force a list of values returned by test into an array
reference. Using \test() will actually do nothing, and if you would
have written it as:

my $arr_ref = \&test();

You would have created a reference to the subroutine 'test';

Aukjan

Thanks!
 
J

John W. Krahn

Aukjan said:
To correct myself... "my $ref = \test()" will actually return a
reference to the last returned value in the list.

test() returns a list and \test() will return a list of references to the
items in the original list. Only the last item will be stored in the scalar
because that is the way that scalar assignment works with a list.


John
 
H

howa

John W. Krahn 寫é“:
test() returns a list and \test() will return a list of references to the
items in the original list. Only the last item will be stored in the scalar
because that is the way that scalar assignment works with a list.

in fact, what does "\test()" means as it is not the reference to the
list returning from the function?
 
P

Paul Lalli

howa said:
John W. Krahn 寫é“:
in fact, what does "\test()" means as it is not the reference to the
list returning from the function?

It means exactly what John said: it would return a list of references
to the items. That is, if the items are ($x, $y, $z), then \($x, $y,
$z) is the same as (\$x, \$y, \$z). But since you were calling \test()
in a scalar context, you were effectively doing:
$test = (\$x, \$y, \$z);

In scalar context, the comma operator returns its right-most element.
In this case, that's \$z. In your case, that's a reference to the
value 3.

Please note there is no such thing as a "reference to a list".

Paul Lalli
 
D

David Squire

howa said:
hi,

consider the program, why reference to an array returning from a
function did not work?

If I were doing this, I would have the subroutine return an array ref:
#------------------------------

sub test {

my @arr = ("1", "2", "3");
return @arr;

return \@arr;
}

my $size = test();
my @arr = test();

my $arr_ref = \test();

my $arr_ref = test();
 
H

howa

David said:
If I were doing this, I would have the subroutine return an array ref:


return \@arr;


my $arr_ref = test();

yes you are right, i just wonder why syntaxically my way is not
allowed....
 
P

Paul Lalli

howa said:
yes you are right, i just wonder why syntaxically my way is not
allowed....

Because your way syntactically means something completely different. A
\ applied to a list means "create a list with references to each item".
It does not mean "create a reference to an array that contains these
items." This has now been explained to you four different times by
three different people. What are you not understanding about it?

Paul Lalli
 
H

howa

Paul said:
Because your way syntactically means something completely different. A
\ applied to a list means "create a list with references to each item".
It does not mean "create a reference to an array that contains these
items." This has now been explained to you four different times by
three different people. What are you not understanding about it?

Paul Lalli

i really don't understand their difference...i suppose they "should" be
the same

1. return \@arr; assign to $arr_ref

2. return @arr, assigh \test() to $arr_ref
 
S

Sherm Pendley

howa said:
i really don't understand their difference...i suppose they "should" be
the same

1. return \@arr; assign to $arr_ref

2. return @arr, assigh \test() to $arr_ref

I think I see what's tripping you up. Unlike C and similar languages, Perl
can return a list of values. So if test() returns @arr, what's on the stack
is not a single array value (an AV* internally), it's one or more scalar
values (SV*).

That's a critical difference, because \test() takes a reference to each of
the return value(s) that test() placed on the stack. So when test() places
multiple scalars on the stack, the result of \test() will be a list of scalar
references, not a single array reference.

If you want test() to return an array reference, you need to do that inside
of test() itself, like this:

sub test {
my @arr = ( 'foo', 'bar', 'baz' );
return \@arr;
}

sherm--
 
D

David Squire

howa said:
i really don't understand their difference...i suppose they "should" be
the same

No. I suspect that your misunderstanding perhaps stems from thinking
that a list and an array are the same thing. They are not.
1. return \@arr; assign to $arr_ref

In this case, the function test() returns a reference to an array - a
variable that was created in the body of test(). test() is thus a
function that returns a scalar.
2. return @arr,

In this case test() returns a *list*, which contains the elements that
are stored in the array @arr, but it is not the same thing as @arr
assigh \test() to $arr_ref

Now you have a problem. test() returns a list. You apply \ to this list,
which returns a list of references to the elements of the list. Then you
assign this list to the scalar $array_ref. When you assign a list to a
scalar, you end up with the last element of the list (which is a
reference to the last thing in the list returned by test() ). Not what
you wanted at all.

Consider:

@foo = ('a', 'b', $bar);

$scalar1 = @foo; # $scalar1 = 3

$scalar2 = ('a', 'b', $bar); # $scalar2 = $bar

$scalar3 = \@foo; # $scalar3 holds a reference to the array @foo

$scalar4 = \('a', 'b', $bar); # $scalar4 holds a reference to $bar

Perhaps this SBCS will make it ever clearer:

----

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

my @foo = ('a', 'fine', 'kettle', 'of', 'fish');
my ($x, $y, $z) = \('bib', 'bob', @foo);
my $q = \('bib', 'bob', @foo);

print $$x, ' ';
foreach my $element (@$z) {
print "$element ";
}
print "\n";

print $$y, ' ';
foreach my $element (@$q) {
print "$element ";
}

----

Output:

bib a fine kettle of fish
bob a fine kettle of fish
 
H

howa

Chris Mattern 寫é“:
Your basic problem is that you think you're returning an array, or a
reference to an array, and you're not. You can't.

A subroutine returns a list. Always, and only, a list.

You can have it return a list whose only element is a reference to
an array, which is what is done in 1. Or you can have it return a
list that you mean to load into an array. If you do the latter, you
can then load that list into an anonymous array and get the reference
to that array, which Aukjan described how to do upthread. You
*can't* get a reference to the list, because there's no such thing
as a reference to a list.


CHris Mattern

hi all,

i now understand my problem as in language such as c or java, there are
no such thing as returning a list!

thanks all guy!
 
P

Paul Lalli

David said:
In this case test() returns a *list*, which contains the elements that
are stored in the array @arr, but it is not the same thing as @arr

That's not strictly true. test() returns @arr. @arr is evaluated in
whatever context test() was called in. If called in list context, @arr
is evaluated to be the list of items @arr contains. If called in
scalar context, @arr is evaluated to be the number of items @arr
contains. Example:

$ perl -e'
sub bar {
@foo = (qw/a b c/);
return @foo;
}

my $x = bar();
print "$x\n";
'
3
Now you have a problem. test() returns a list. You apply \ to this list,

You've got it backwards. test() returned @arr. The \ that was in
front of test() imposed list context on the call to test(), causing
@arr to be called in list context. Assinging the results of test() to
a scalar causes the list that was returned to be evaluated in scalar
context, which means to return the last element of that list.
 
P

Paul Lalli

Sherm said:
Actually, it is - ask any XS programmer. If you attempt to return an array
or hash from a sub, what perl pushes onto the stack is a list of SV*s, not
the AV* or HV* itself.

Poor choice of response on my part. My point was intended to be that
simply saying "return @arr" does not guarantee that any of the items
contained in @arr are going to end up in the variable(s) that are
assigned to the subroutine call. If the call itself is in scalar
context, then @arr is evaluated in scalar context. I have not yet read
the documentation you pointed me to, so I can only assume that in this
case, the list returned from the subroutine is infact a list containing
one element - the size of @arr.
Have a look at "perldoc perlcall" for the gory details.

Thanks for the pointer. I'll delve into it when I have more time (and
am feeling slightly masochistic.... )

Paul Lalli
 
D

David Squire

Paul said:
Poor choice of response on my part. My point was intended to be that
simply saying "return @arr" does not guarantee that any of the items
contained in @arr are going to end up in the variable(s) that are
assigned to the subroutine call. If the call itself is in scalar
context, then @arr is evaluated in scalar context. I have not yet read
the documentation you pointed me to, so I can only assume that in this
case, the list returned from the subroutine is infact a list containing
one element - the size of @arr.

True, and, to me, surprising. This implies that the subroutine knows the
context in which it was called, which seems to me to break all sorts of
principals of encapsulation, low coupling, etc.


DS
 
D

David Squire

David said:
True, and, to me, surprising. This implies that the subroutine knows the
context in which it was called, which seems to me to break all sorts of
principals of encapsulation, low coupling, etc.

.... or even "principles" :(
 
H

howa

howa 寫é“:
Chris Mattern 寫é“:


hi all,

i now understand my problem as in language such as c or java, there are
no such thing as returning a list!

thanks all guy!

one of the interesting finding is that perl will use reference
internally...

e.g.

sub test {
my @arr = ("1", "2", "3");

foreach my $a(@arr) {
print \$a . "\n";
}
return @arr;
}

my @arr = test();

foreach my $a(@arr) {
print \$a . "\n";
}
 
C

Ch Lamprecht

howa said:
howa 寫é“:


one of the interesting finding is that perl will use reference
internally...

e.g.

sub test {
my @arr = ("1", "2", "3");

foreach my $a(@arr) {
print \$a . "\n";
}
return @arr;
}

my @arr = test();

foreach my $a(@arr) {
print \$a . "\n";
}
this printed:

SCALAR(0x186d03c)
SCALAR(0x186d048)
SCALAR(0x186d054)
SCALAR(0x186d03c)
SCALAR(0x186d048)
SCALAR(0x186d054)


But:

The only thing you can see is, that the addresses are the same. @arr inside of
test() is out of scope when the function returns. Might be by chance, that the
same addresses are reused:

Check this example:

use strict;
use warnings;

sub test {
my @arr = ("1", "2", "3");

foreach my $a(@arr) {
print \$a . "\n";
}
return @arr;
}

my @arr = (0..100);

@arr = test();

foreach my $a(@arr) {
print \$a . "\n";
}



prints:

SCALAR(0x1868548)
SCALAR(0x1868554)
SCALAR(0x1868560)
SCALAR(0x225038)
SCALAR(0x225194)
SCALAR(0x225254)


Christoph
 
T

Tad McClellan

David Squire said:
This implies that the subroutine knows the
context in which it was called,


So you can make your own subroutines that have different scalar context
vs. list context behaviors, just like Perl's builtin functions do.

perldoc -f wantarray
 
S

Sherm Pendley

David Squire said:
True, and, to me, surprising. This implies that the subroutine knows
the context in which it was called

It does - have a look at "perldoc -f wantarray".

sherm--
 

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,995
Messages
2,570,230
Members
46,816
Latest member
SapanaCarpetStudio

Latest Threads

Top