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

This is one of those "I feel stupid for asking" questions because I'm sure the answer is obvious. I suspect it's the combined pressure of both American Idol and 24 which is causing this blockage. But I digress...

I have a subroutine. I want it to be able to take either an array, or a reference to an array. The subroutine itself does its work on an array, so the question becomes one about how to best stuff the input to a subroutine into an array, regardless of whether the input is an array, or a reference to an array.

Here's what I've got so far:
sub thinger{ return unless $_[0]; my @array; if((scalar @_) == 1){ return $_[0] unless ref($_[0]); @array = @{$_[0]}; } else{ @array = @_; } # Do something important sleep 30000; return wantarray ? @array : \@array; }
Is that how it's done? Or is there some better way to determine whether I'm getting an array or an arrayref passed to the routine? Keep in mind I'm interested in how to get @array populated, not what is done with it or how it's returned.

Thanks

Replies are listed 'Best First'.
Re: Detecting Subroutine Input Type
by ysth (Canon) on May 03, 2004 at 06:14 UTC
    This problem is not solvable without placing restrictions on what can be in the array or how the array reference looks.

    In your solution above, you distinguish based on number of arguments passed, which prevents you from passing an array of one element (which may or may not be just fine for your purpose).

    You could instead choose to check the ref type of the parameter: if (ref $_[0] eq "ARRAY") { ... } else { ... } which would prevent you from passing an array whose first element was an array reference. (Variations on this involve UNIVERSAL::isa($_[0], "ARRAY") or calling an isa method on an object or doing an array dereference in an eval block to see if it fails; this subproblem of "what is an array reference" also has no perfect solution.)

    Or combine both the check for one element and the check for an array ref.

    There are also prototypes; if you promise to not use them as if they were what other languages call prototypes,

    All in all, it's best to document what your routine expects and take only that input; do you really need to accept both?

Re: Detecting Subroutine Input Type
by Chady (Priest) on May 03, 2004 at 06:07 UTC

    You need ref, like so:

    sub thinger { my @array; if (ref($_[0]) eq 'ARRAY') { @array = @$_[0]; } else { @array = @_; } ... }

    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady | http://chady.net/
      sub thinger { my @array = ( ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_ ); }
      Well duh! Thanks Chady (and Anon), that's what I was thinking of. Much better than what I was doing.
Re: Detecting Subroutine Input Type
by Mr. Muskrat (Canon) on May 03, 2004 at 06:11 UTC

    I think that you should check the length of @_ and if it is 1, then make sure that that one item is not only a reference but a refernce to an array.

    sub regardless { return unless @_; my @array = @_; if (@array == 1) { my $ref = ref($array[0]); if ($ref) { return unless ($ref eq 'ARRAY'); @array = @{$array[0]}; } } return wantarray ? @array : \@array; }