telcontar has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I must admit that I'm rather new at Perl, and keep having silly problems like this one. I hope you can enlighten me as to what I am doing wrong here:

sub x { my @a = (1, 2, 3) } sub y { \&x(); } my $h = &y; print "@$h\n";
The sub y is supposed to return a reference to the array returned by the sub x. However, although I get a reference, this isn't an arrayref (and it's not a coderef either).

Of course,

sub y { my @blah = &x(); \@blah }

works, but somehow that seems like too much code.

Any help would be appreciated.

John

Replies are listed 'Best First'.
Re: return a ref to a return value (array) of another sub
by Zaxo (Archbishop) on Apr 11, 2005 at 17:23 UTC

    This will make sure that sub x is called in list context: sub y { [ x() ] } It produces a reference to a array copy of x()'s returned list.

    After Compline,
    Zaxo

Re: return a ref to a return value (array) of another sub
by Fletch (Bishop) on Apr 11, 2005 at 17:25 UTC

    x isn't returning an array, it's returning a list of values. Don't feel bad, as the array / list distinction can be a fine one and you've just hit smack into it. Either x could return an array reference itself which y would return verbatim (although that'd be somewhat inefficient unless it did something else as well as call x); or you could use the anonymous array constructor [] in y

    sub x { my @a = ( 1, 2, 3 ); \@a } sub y { x() } ## or sub x { my @a = ( 1, 2, 3 ); } sub y { [ x( ) ] }

    Note that in the second case x still is returning a LIST, not an ARRAY; y just packages that returned list of values up in a new (anonymous) array.

Re: return a ref to a return value (array) of another sub
by gaal (Parson) on Apr 11, 2005 at 17:27 UTC
    First of all, avoid "y" as a name for a function, since it is a keyword.

    \&x() evaluates, like \(1, 2, 3) does, to a list of references to the values in the original list: (\1, \2, \3). See perlref.

    You can construct an anonymous array and have your second function (I'll call it "yy") return a reference to that:

    sub yy { [ x() ] }

    (Avoid "&" except when you really need it.)

Re: return a ref to a return value (array) of another sub
by Joost (Canon) on Apr 11, 2005 at 17:39 UTC
    Your making an assumption that turns out to be wrong :-)

    First:

    sub y { \&x(); }
    Returns a reference to whatever x() returns *) but functions can not return plain arrays; they returns lists or single (scalar) values, depending on how they're called (this is called context in perl).

    update: the following is wrong, since \ forces list-context on its argument

    If x() would return a list, y() would return a list of references to those values, but that's not what is happening here.

    Since you're doing

    my $h = &y;
    y() is called in scalar (in stead of list) context. the context is propagated to the returning statement in y() - that's \&x();. That propagates the scalar context up to the my @a = (1,2,3) statement. That statement is a list assignment, and a list assignment in scalar context returns the number of values assigned.

    So, x() returns 3, and then you take a reference to that and return it from y() and assign it to $h.

    Then you try to derefence $h as an array reference, but since $h contains a reference to a scalar, that won't work.

    update: the rest is correct, though

    The quickest fix would be:

    sub y { [ x() ]; }

    Which creates a new anynomous array containing all the values returned by x() in list context.

    *) Personally I think using \&sub(); is really confusing, since \⊂ without parens returns a reference to the subroutine; generally I think it's better to never use &sub(); for calling subroutines, since ⊂ can also cause confusion - see perlsub. In essence, you only need & for taking a reference to a sub, or other special cases, and you probably should use sub(); ( or sub; ) for all "normal" cases.

Re: return a ref to a return value (array) of another sub
by BrowserUk (Patriarch) on Apr 11, 2005 at 17:23 UTC

    sub y{ return [ x() ]; }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco.
    Rule 1 has a caveat! -- Who broke the cabal?
Re: return a ref to a return value (array) of another sub
by Roy Johnson (Monsignor) on Apr 11, 2005 at 17:27 UTC
    Subroutines cannot return arrays, they can return lists. When you put a backslash in front of a list, Perl turns it into a list of references to whatever made up the list. It's a convenience feature.

    You could either have x return an array ref, or you could have y put the results of x into an array ref

    sub x { [my @a = (1, 2, 3)] }; # or sub y { [&x()] } # The & is unnecessary, though

    Caution: Contents may have been coded under pressure.