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

I'm returning multiple values from one of my functions with strange results... this is a snippet from the end of the sub. the hash %results is correctly constructed here.. and the value of $type is what is to be expected.
my %results; my $type = "XXX"; while(my @row = $sth->fetchrow_array) {$results{$row[0]} = $row[1];} return (%results,$type);
however when calling the function in this manner
my (%results, $type) = findResults();
$type is undef and %results has the value of the $type stuck in the middle of the hash with aparently a null key.. The rest of the hash contains the corect values. does anyone have any idea why this would be? I can be more specific if need be..
editing the actual content of your script for privacy reasons is a pain, so I tried to give as much detail as I could w/o rewriting the script with non-descript names.

Replies are listed 'Best First'.
•Re: Returning multiple values from a function
by merlyn (Sage) on Sep 03, 2003 at 18:08 UTC
    You can return only a scalar or a list from a function. To get a hash return, you either have to flatten it into a list (and reconstruct it at the other side) or return a reference to the hash.

    Perhaps you want:

    return \%results, $type;
    and
    my ($results_hashref, $type) = findResults(); foreach my $key (sort keys %$results_hashref) { ... } # etc

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Returning multiple values from a function
by Limbic~Region (Chancellor) on Sep 03, 2003 at 18:13 UTC
    Grygonos,
    You have been bitten by the slurpy nature of things. You could probably just correct your problem by doing:
    my ($type, %results) = findResults(); #More code return ($type, %results);
    This is because things are passed back and forth between subs in flattened lists - how does it no where to stop with an array, start with a scalar, and finish with another hash?

    As a side note - you should probably look into passing references around instead of full blown hashes and arrays if they are going to grow to any size. This accomplishes two things - everything is a scalar and there is no copying back and forth to speak of. Well three actually. The technique I showed only works if you have a bunch of scalars and then only one slurpy thing (array/hash). If you have multiple slurpy type thingies (love my technical jargon) - you have to use references.

    Cheers - L~R

      ok thanks for your input. I corrected the problem in a doofangled way.. I passed type by reference to the function and only returned the hash. I don't know if I like it but it works atm.

      Here is my next question. If I get a scalar hashref back from that function like so,  $mynewref = findResults() do i simply pass that ref to another function who needs access to the hash data. ie. assignResultSet($mynewref); and then simply treat it as a hashref inside the sub? I wouldn't think you would pass it as a ref again because then you would need to doubly deref it unless i'm mistaken. That is my hunch but I'm not sure if that's the correct/accepted way to do it

        Grygonos,
        Ok - for all intents and purposes, a reference is like a card from the card catalog in a library. The card tells you exactly where to go get the book you are looking for. You can de-reference (go get the book) anytime you like. This means you could pass the reference to the second sub or dereference back to the hash and pass that - it is completely up to you. If you pass a reference, the sub will need to know how to properly dereference it when it needs it.

        Since it doesn't take very long to get used to using the proper syntax, I prefer passing by reference as a rule.

        Cheers - L~R

        ok thanks for your input. I corrected the problem in a doofangled way.. I passed type by reference to the function and only returned the hash. I don't know if I like it but it works atm.

        Be careful about what you pass around, and what you return. As others already said, your parameter list gets flattened out into a list. If you return a hash, the hash gets flattened out, but if you accept the results of the call back into hash, then you are all right. NOTE: This all changes if you have a hash as one of many parameters that you are passing to a subroutine, or returning from a subroutine. If you are passing mixed parameters (scalars, lists, hashs), then your subroutine can get confused.

        The safest way to pass (or return) arrays and hashes is by reference. This keeps your parameter list all scalars, since a reference is a scalar.

        sub test { my $scalar1 = shift; my $array2_ref = shift; my $hash3_ref = shift; ### if you want to work with the hash, and not just ### the hash reference, then dereference the ref. my %hash3 = %$hash3_ref; print "value for hash key 'one' is $hash3{'one'}\n"; ### I prefer to just use the reference instead, and ### not create the hash by dereferencing the hash ref. print "value for hash key 'one' is $hash3_ref->{'one'}\n"; return($scalar1, $array2_ref, $hash3_ref); } my $test_scalar = "abc"; my @test_array = ( "a", "b", "c" ); my %test_hash = ( "a" => 1, "b" => 2, "c" => 3 ); ($new_scalar, $new_arrayref, $new_hashref) = test($test_scalar, \@test +_array, \%test_hash);
        Sorry, now that I've preview'd my response, I can't see what your next question was.

        HTH.