How do I return a %hash from a subroutine

Tonyboy
Tonyboy used Ask the Experts™
on
Hi,

I must have missed a key lesson when learning Perl, because I can't figure out how to return a hash from a subroutine. Consider the following:

%hash = &gethash();
print join(', ', keys %hash);

sub gethash {
   return ( 'apple' => 'red', 'banana' => 'yellow', 'kiwi' => 'brown' );
}

That works fine, and the output is as follows:
> apple, banana, kiwi

Now, I would like to skip the %hash step, and simply do something like:
print join(', ', keys %gethash);

That doesn't work, and no combination of %, @, {}, () symbols I've tried have yielded anything valid. I'd eventually like to be able to do:

print join(', ', values ( &gethash() ){ @keys });


I don't want to use a hash reference, if at all possible, because this problem has been haunting me all morning, and I need to know what I'm missing.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
>> print join(', ', keys %gethash);
Won't work because the argument to keys needs to be a hash not a subroutine.

>> I don't want to use a hash reference, if at all possible
Why


I don't understand your purpose in using that subroutine.  Is your sub doing someting else (i.e., did you leave out some code) prior to the return statment?

This is a more common method for a sub to return a hash:
return %myhash;
Could you give us more details on what you are needing to accomplish?  Could you include a more complete example of your code so that we can better understand what your doing and possibly come up with another approach?

Author

Commented:
FishMonger,

The original join() statement you quote contains a typo on my part. That should read:
> print join(', ', &gethash() );

Yes, my &gethash() subroutine is more complicated, and extracts information from a file, processes it, and returns a hash.

The point is not what I'm trying to do overall, though. I provided the simplest example I could because I don't really want to come up with a "work-around", but rather I would like to understand how to make keys() understand that I'm dealing with a hash. It's not so much the ends that I'm interested in, it's the means to that end.

Cheers,
- Tonyboy
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

Based on my experience and all the Perl books that I have, you need to use %hash as the argument to keys and values not a subroutine call that returns a hash.  So, I think you'll to need use, print join(', ', keys %hash);  or  print join(', ', values %hash);

>> I would like to understand how to make keys() understand that I'm dealing with a hash
The keys and values functions only work directly on hashes and nothing else.

Author

Commented:
No, I disagree with your last point, because this would work:

print join(', ', ( &somesub() )[0..3]);

sub somesub {
      return qw(1 2 3 4 5);
}

If I can interpret the results of &somesub as an array, and even deal with a slice from that array, then surely getting a slice from a hash isn't that far off.

Nevertheless, I have a sneaking suspicion that you may be right, and that there isn't really a way to do what I want. I will leave this thread open for a few more days, and if I don't find a definitive answer, I'll award you the points.

Thanks for your help.
The difference in that example is that your not using the keys or values functions, they are the ones that are not allowing you to use the subrouting call.  The join function is designed to allow a function call as one of its arguments.
Perl programmer, author and trainer
Commented:
Well it's a bit kludgy and it does make use of a hash reference (but it's a bit hidden so you might let me get away with it).

#!/usr/bin/perl
                                                                             
use strict;
use warnings;
                                                                             
sub gethash {
  return apple => 'red', banana => 'yellow', kiwi => 'brown';
}
                                                                             
print join ',', keys %{ {gethash()} };

gethash() returns a list, the inner pair of { ... } turns the list into an anonymous and returns a reference to it, the %{ ... } dereferences the anonymous hash reference so that you can use it as the argument to keys.

Nasy kludge. But it works :)

Dave...
Well, hush my mouth.  I would have sworn that you couldn't use the sub as an arg to keys but hiding it like that works.  I learn something new every day.

Commented:
bah. davorg beat me to it =)

Author

Commented:
davorg,

Yes, I agree that you solution is a bit klunky, but clearly, it's a work-around for a design flaw in Perl. If the only way to convince Perl that the values returned by a subroutine is by referencing and then dereferencing the data as a hash, then it's clear to me that Perl needs to be more conscious of data types internally.

Many thanks to all,
- Tonyboy
Dave CrossPerl programmer, author and trainer

Commented:
Perl subroutines only ever return a scalar or a list. Not an array or a hash. You can, of course, assign the returned list to an array or a hash (or a list of scalars). You can also    ta
Dave CrossPerl programmer, author and trainer

Commented:
Oops... what I was going to say was...

You can also take a _list_ slice of the retun list n as the syntax for a list slice looks a lot like an array slice some people get them confused.

Dave...

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial