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

Brothers and Sisters: This may be dismissed as a stupid newbie error, but I have a problem that my own resources have yet to resolve.

Essentially, I have a subroutine that is pulling in data from a mysql database, returing things that match in an array, counting the matches, and then returning both the array and the count. Basically, here's how it looks now:

(@ary1, $num) = read_data(\@tmpary, $tmpsclr); ... sub read_data { ... do stuff with @retary and $count return @retary, $count; }

I have been all over in the Holy Camel Book, and the most I can find is info about returning multiple hashes or arrays, and nothing regarding an array and a scalar together. Any help would be appreciated.

Brother Descartes

-- Programmus, ergo sum.

Replies are listed 'Best First'.
Re: Arrays and Scalar Parameters
by VSarkiss (Monsignor) on Aug 20, 2001 at 22:44 UTC

    The reason this won't work the way you think: (@ary1, $num) = read_data(\@tmpary, $tmpsclr);is documented in the documentation on subs. The return from a sub is always a flat list. Perl shoves everything into @ary1, leaving $num empty.

    A reasonable alternative is to return an array ref and a scalar:

    ($ary1ref, $num) = read_data(...); @ary1 = @$ary1ref; # silly, but gets the point across # ... later ... sub read_data { # ... return \@retary, $count; }

    HTH

Re: Arrays and Scalar Parameters
by Sifmole (Chaplain) on Aug 20, 2001 at 22:36 UTC
    I have used two major methods of returning multiple values from a method.

    First, if you know that the first n will be your array and the last will be a seperate value then you can use that when picking up your information.

    #callMult returning an array and a scalar my @ret = callMult(); my $foo = pop @ret;
    However this code can become confusing. I prefer to handle this by returning references for structures.
    sub callMult { return \@result, $count; } my ($result, $count) = callMult(); # you can then use $result->[$i]; # to access the array elements # or @result_array = @$result; # to dereference it
Re: Arrays and Scalar Parameters
by ozone (Friar) on Aug 20, 2001 at 22:44 UTC

    You can't easily return an array and a scalar - the array is going to consume all the returned values (the scalar included).

    In this case it's best to just return a ref to the array as well as the scalar like so:

    sub do_something { ... return \@someValues, $someValue; } ($someValues_aref, $endValue) = do_something();
    Without using references you would have to do something like this:
    (@someValues) = do_something(); $endValue = pop(@someValues);
    Messy, but it would get the job done.
Re: Arrays and Scalar Parameters
by kjherron (Pilgrim) on Aug 20, 2001 at 22:49 UTC
    Your return statement
    return @retary, $count;
    is going to mash the contents of the array and the value of $count into a single list of values. When this is assigned to (@ary1, $num), all of the values will be put into @ary1.

    There are two ways to accomplish what you're trying to do. First, you can pass $count before the array contents:

    return $count, @retary; ... ($count, @ary1) = read_data(...);
    This method still lets you return only one array.

    The other method is to return a reference to @retary instead of returning the array's contents:

    return \@retary, $count; ... ($ary1, $count) = read_data(...);
    This allows you to return any number of arrays and scalars in any order. It's also more efficient because read_data() is returning a two-value list instead of a fifty- or hundred- or whatever-value list.

    Finally, let me add that, if $count is just the number of elements in @retary, there's really no need to pass it as a separate value. The caller can derive the size of the array from the array itself:

    @ary1 = read_data(...); $num = @ary1; OR $ary1 = read_data(...); $num = @$ary1;
Re: Arrays and Scalar Parameters
by IraTarball (Monk) on Aug 20, 2001 at 22:51 UTC
    I believe that the problem here, as alluded to in Sifmole's post, is that the values are all being returned as a single list. It might be safest to use references as Sifmole says, but for something like what you have here you can get away with just changing the order of the return data.
    use strict; use warnings; sub getStuff { return 6, qw(one two three four five six) } my ($thing, @list) = getStuff(); print "my thing is $thing\n"; print "my list is @list\n";
    This prints out:
    $ perl list.pl my thing is 6 my list is one two three four five six

    Hope this helps,
    Ira,

    "So... What do all these little arrows mean?"
    ~unknown

Re: Arrays and Scalar Parameters
by Cine (Friar) on Aug 20, 2001 at 22:54 UTC
    You could just turn the scalar and array around:
    ... return $count,@retary; ... ($num,@ary1)=blablabla
    Reason is that the array eats everything and let $num undef, but the other way around you eat $num first and then let the array eat the rest...

    T I M T O W T D I
Re: Arrays and Scalar Parameters
by descartes (Friar) on Aug 20, 2001 at 23:20 UTC

    Thanks for all your suggestions. Reversing the scalar and array worked great, and the other ideas I'll keep for if I need to return mixed and multiple.

    Brother Descartes

    -- Programmus, ergo sum.
Re: Arrays and Scalar Parameters
by dga (Hermit) on Aug 21, 2001 at 00:04 UTC

    Why return the count at all?

    If the caller wants the count it can get it directly from the returned array.

    #useful caller code goes here my(@arr,$count); @arr=myfunction(); $count=@arr; #more caller here

    An array evaluated in a scalar context such as assigning to a scalar gives the number of elements in the array.

    Update: seems that this is bad for some reason. The question could have been (or probably will be read by) new perl users and so knowing that you need not return the count of an array to access it is valuable? The original node said nothing about the array being multidimensional.

      The reason for returning a count is that the returned array is multi-dimensional, and while I could just divide the array count by the number of fields, if the table changed in the future, it would could potentially be a pain for someone else to debug.

      Brother Descartes

      -- Programmus, ergo sum.
Re: Arrays and Scalar Parameters
by John M. Dlugosz (Monsignor) on Aug 21, 2001 at 08:01 UTC
    Everyone's told you how to return two values. Here is another idea: return an object instead. The object encapsulates the multidimentional array in toto, and provides a good way to access it without having to understand the layout directly.

    —John