2

Hey. In Python I can do this:

def fnuh():
    a = "foo"
    b = "bar"
    return a,b

Can I return a list in a similarly elegant way in perl, especially when the return type of the subroutine should be a reference to an array?

I know I can do

sub fnuh {
    my $a = "foo";
    my $b = "bar";
    my $return = [];
    push (@{$return}, $a);
    push (@{$return}, $b);
    return $return;
}

But I bet there is a better way to do that in Perl. Do you know it?

6
  • 2
    Be careful about the distinction between lists and arrays. This is an area that causes a lot of confusion. Understanding the distinction is important for understanding how context works. See perldoc.perl.org/… and perlmonks.org/?node_id=130861 and perlmonks.org/?node_id=719099 for some discussion. Commented Jan 14, 2010 at 16:43
  • 2
    Thanks, I thought that this had to involve lists, but actually the solution I like best - return [$a, $b] - does not involve one. If you know of a better way to state the intent of the question let me know. Commented Jan 14, 2010 at 17:02
  • Your question is fine. In most languages there is no real distinction between a list and an array. Perl is makes a distinction. A list is an ordered group of values. An array is a variable data type that contains an ordered set of values accessible by index. Your preferred answer is doing precisely what you asked for. I was just trying to emphasize the distinction between arrays and lists. It is a subtle thing, but getting it really does help with understanding how context works in Perl. Commented Jan 14, 2010 at 17:22
  • 2
    Your solution does involve a list. This is the subtlety I mentioned. Let's look at what [$a, $b] is doing. First we have the anonymous array constructor [ EXPRESSION ], it evaluates the expression in list context and uses the results to populate an array ref. Next is the expression $a, $b. In scalar context, the expression evaluates to $b (the rightmost element-see the comma operator in perlop). In list context, both values are returned. So the anonymous array ref is populated with two values, $a and $b. Which is almost too much pedantry for the comment system here to handle. Commented Jan 14, 2010 at 17:38
  • thanks for the clarification. But now I want a button to hide all comments ;-).. Commented Jan 14, 2010 at 18:20

3 Answers 3

8

Sure, just slap a \ in front of the list to return a reference.

Or make a new arrayref with [ list elements ].

In your example,

sub f1 {
    my $a = "foo";
    my $b = "bar";
    return [ $a, $b ];
}

sub f2 {
    my $a = "foo";
    my $b = "bar";
    push @return, $a, $b;
    return \@return;
}

Please see perldoc perlreftut and perldoc perlref for more about references. There is also a data structures cookbook at perldoc perldsc.

You may also want to read this question in the perlfaq (thanks brian): "What's the difference between a list and an array?"

Sign up to request clarification or add additional context in comments.

9 Comments

The second way you definitely want to declare @return with my, otherwise it becomes global which is not so good.
"# the last expression is returned automatically; no need to be explicit" - regarding this, I like python better. From "the zen of python", second statement: Explicit is better than implicit. So I would prefer: return [$a, $b];
I prefer to always do explicit returns. There's nothing wrong with adding a bit of clarity. Especially in Perl. :)
The thing python fans fail to realize is that the Zen of Python is load of crap. Imagine reading a sentence if you had to be explicit and encode what each part of the sentence the word was and where it was positionally located. FIN := (noun,statement;terminating word)
Perl Best Practices, Chapter 9, Item: Implicit Returns: "Always return via an explicit return". I don't think that Damian Conway prefers Python, but he is on my side here.
|
6

Python automatically packs and unpacks tuples around an assignment simulating lists. In Perl, you can write it the same way, returning a list.

sub fnuh {
    my $a = 'foo';
    my $b = 'bar';
    $a, $b
}

then to use the result:

my ($x, $y) = fnuh;

or if you need the reference:

my $ref = [ fnuh ];

4 Comments

I like the simplicity of this answer. Also, wantarray.
some more pedantry: Perl Best Practices, Chapter 2: Code Layout, Semicolons: "Place a semicolon after every statement". Chapter 4: Values and Expressions, Lists: "Parenthesize every raw list". The minimalist in me likes the terse syntax, though.
Perl Best Practices isn't the Holy Bible. It's what Damian likes to do. It doesn't mean that you have to do it. See my interview with him: theperlreview.com/Interviews/damian-bpp-20050622.html
I prefer to explicitly leave the semicolon off the last line when not using the return keyword. That way, if any code is ever placed after that line it will likely be a syntax error. It also reinforces the fact that without a return, subs return their last statement. I find that many of the guidelines in PBP are defensive techniques that call back to a day before decent real time syntax checking.
-1

You can get the same function as Python by explicitly testing whether the context wants an array with the function wantarray.

sub fnuh {
    my $a = 'foo';
    my $b = 'bar';
    return wantarray ? ( $a, $b ), [ $a, $b ];
}

Or if you want to do this a lot, you could write a function that will be able to read the same context, as long as you have not altered it.

sub pack_list { 
    my $want = wantarray; 
    return unless defined $want; # void context
    return $want ? @_ : \@_;
}

Then call it like this:

return pack_list( $a, $b );

2 Comments

Dealing with contexts in Perl is best way to shoot yourself to foot.
@ Hynek -Pichi- Vychodil: I'm not sure why you say that. Context is one of the things I like best in Perl. When I work in Java, I often wish I could do the same thing without extra parameter passing and overloading. If you're not familiar with context, it can be confusing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.