3

I have the following sub-routine.

 sub Function{
   my $ref = \($_[0]);
   if(ref($ref) eq 'SCALAR'){
   . . .
   }
}

I am trying to get it to work such that passing a list, scalar or hash to it, it converts that into a reference and depending upon whether that reference is of type ARRAY, SCALAR or HASH, different actions are performed.

It could be called as

Function(%a)
Function($a)
Function(@a)

How can I make $ref be a reference to whatever is passed to the Function? My current approach isn't working.

0

3 Answers 3

6
Function(%a)
Function($a)
Function(@a)

You can't do what you are asking. There is no way inside Function to determine whether an array or a hash was passed, because, in fact, you can't pass an array or a hash to a sub in the first place. You can only pass a list; the hashes and arrays are converted to lists in the sub calls above.

You should pass a reference to the function in the first place:

Function(\%a)
Function($a)
Function(\@a)

Then you can check what it is easily:

sub Function {
  my $param = shift;
  if (not ref $param) {
     ...
  } elsif (ref $param eq 'HASH') {
     ...
  } elsif (ref $param eq 'ARRAY') {
     ...
  }
Sign up to request clarification or add additional context in comments.

2 Comments

I understood that :) Thanks. But there is a way to pass the array or hash-ref, even if array or hash is passed by user. (stackoverflow.com/a/12583728/759019)
@DarkXphenomenon It's really quite hackish though. Why can't you pass a reference instead of a list? Are you working with legacy code? If so, I could see why you would want amon's solution, but, in new code, it is not a good design.
3

You can use a prototyped function. Although Perl 5 prototypes are a total mess, they can be used quite well in this case. As I understand them the prototype

sub Function (\[$@%]) {...}

should solve your problem, and the reference be in $_[0].

The big disadvantage is that the variable you pass has to start with the $, @, or % character, so you can't call Function with a constant argument directly:

 Function(1)

fails, but

 my $temp = 1;
 Function($temp)

works.


Your approach failes, because @_ is a list, and all elements are scalars.

7 Comments

I understand why $_[0] failed previously. Thanks! I am using that Function() recursively and it is failing when I use the above prototype with the error Function called too early to check prototype when trying to recurse.
@DarkXphenomenon then use subs 'Function' at the beginning of the module/file to force prototype checking
@DarkXphenomenon Yes, but this scalar $_[0] is a reference to the original argument. You can view the contents with print Data::Dumper::Dump $_[0]
Dumper prints it right. The entire array. It is a ref to the original arg. But when I do ref($_[0]), it says SCALAR, even though it is an array I passed.
@DarkXphenomenon For testing purposes, I used this one-liner: perl -MData::Dumper -e'sub Function (\[$@%]) {print $_[0], "\n"; print Dumper $_[0]} @x = (1, 2); Function(@x)' Output: ARRAY(0x8a5bcec) $VAR1 = [1, 2];. And ref is ARRAY.
|
0

Why not just check to see if the argument passed in is a reference and act accordingly?

sub gimme_a_ref
{
  my $arg=shift;

  if(ref $arg ne ref "")
  {
    return $arg;
  }
  else
  {
    return \$arg;
  }
}

8 Comments

given (ref $arg) {return $arg when [qw(ARRAY HASH CODE SCALAR)]; default {return \$arg}} is far cleaner.
or: sub gimme_a_ref { my $arg = shift; return ref $arg ? $arg : \$arg }
my $arg = shift; If I was passing a hash to the function, wouldn't the scalar $arg just contain the first key?
@DarkXphenomenon - Well, what do you want to have happen if @_ > 1? Since => is treated the same as a comma, the subroutine wouldn't know if you intended to pass the elements of @_ as an array (that is not an array ref) or as a hash (that is not a hash ref) (with the exception of passing in an odd number of arguments, of course).
@DarkXphenomenon - It sounds as though you might want to separate your functionality: one subroutine to take a list of arguments that will be treated as a hash, another to take a list of arguments that will be treated as an array, etc.
|

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.