Re: Hashes as return values
by blazar (Canon) on Jan 17, 2006 at 16:02 UTC
|
You can either return a reference to a hash, which probably you don't since you assign to %acls which happens to be a hash, not a hashref, or return a flattened list, then assign it to a hash. But it seems that it is not what you want. Just remember that just like an array is not a list, and the difference is (in a technically imprecise terminology) fundamentally that "the former has a name", the same happens with hashes: a hash in list context is flattened. OTOH each and keys expect a hash, so you must give them a hash, full of its name. But if it is anonymous, then call it by its ehm anonymous name, by dereferencing:
#!/usr/bin/perl -l
use strict;
use warnings;
package Module;
sub new {
bless { ACLS => {foo => 1, bar => 2} }, shift;
}
sub acls {
my $self=shift;
$self->{ACLS}
}
package main;
my $mod=Module->new;
while (my @stuff=each %{ $mod->acls } ) {
print "@stuff";
}
__END__
| [reply] [d/l] [select] |
Re: Hashes as return values
by mrborisguy (Hermit) on Jan 17, 2006 at 15:41 UTC
|
I believe that my %acls = \$self->{ACLS}; is making a reference to the hashref. You would want something like my %acls = %{ $self->{ACLS} }; instead.
-Bryan
| [reply] [d/l] [select] |
|
|
Thanks. However, that didn't quite get it. I made the above change and then tried the following:
foreach(keys $config->acls) {
print "$_";
}
and
while(my ($name, $value) = each $config->acls()) {
print "$name<br>$value<br>";
}
But both returned the error:
"Type of arg 1 to keys must be hash (not subroutine entry)" | [reply] [d/l] [select] |
|
|
The error means exactly what it says, 'keys' needs a hash, not a hashref, or anything else. This works:
use strict;
use warnings;
my $obj = Foo->new();
for my $key (keys %{$obj->{acls}})
{
print "$key\n";
}
package Foo;
sub new
{
my $self = shift;
my %obj = ( acls => { a=>1,
b=>2 } );
return bless \%obj;
}
Note the %{} round $obj->{acls} dereferencing the hashref into a hash.
Update: Just as added clarification, since you were talking about return values from functions:
use strict;
use warnings;
my $obj = Foo->new();
for my $key (keys %{$obj->{acls}})
{
print "$key\n";
}
for my $key (keys %{$obj->acls})
{
print "$key\n";
}
package Foo;
sub new
{
my $self = shift;
my %obj = ( acls => { a=>1,
b=>2 } );
return bless \%obj;
}
sub acls
{
my $self = shift;
return \%{$self->{acls}};
}
The second for loop calls acls() to get at the content of the attribute {acls}, dereferences it, and iterates through printing the keys. The first loop is accessing the hashref directly, rather than through a function call.
--------------------------------------------------------------
"If there is such a phenomenon as absolute evil, it consists in treating another human being as a thing."
John Brunner, "The Shockwave Rider".
| [reply] [d/l] [select] |
Re: Hashes as return values
by thedoe (Monk) on Jan 17, 2006 at 16:06 UTC
|
If $self->{ACLS} is a hashref, then one way to correct this is to return the hashref directly and cast it into a hash in your loop declaration:
sub acls {
my $self = shift;
# my %acls = \$self->{ACLS} # $self->{ACLS} is a hashref
# return %acls;
return $self->{ACLS};
}
foreach(keys %{$mod->acls}) {
# code in here
}
You must make sure to include the extra braces around $mod->acls or it will try to interpret %$mod before $mod->acls. Hope this helps!
| [reply] [d/l] [select] |
Re: Hashes as return values
by NetWallah (Canon) on Jan 17, 2006 at 20:00 UTC
|
Here is yet another way to do this, using callbacks. It simplifies client programming, but requires a coderef to be passed into the method call.
#!/usr/bin/perl -l
use strict;
use warnings;
package Module;
sub new {
bless { ACLS => {foo => 1, bar => 2} }, shift;
}
sub acls {
my ($self , $callbackref) = @_;
while ( my ($k,$v) = each %{ $self->{ACLS} }){
&$callbackref($k,$v);
}
}
package main;
my $mod=Module->new;
$mod->acls (
sub{ print "@_\n"; }
);
---Output---
bar 2
foo 1
You're just jealous cause the voices are only talking to me.
No trees were killed in the sending of this message. However, a large number of electrons were terribly inconvenienced.
| [reply] [d/l] [select] |
Re: Hashes as return values
by dirtdart (Beadle) on Jan 17, 2006 at 16:26 UTC
|
Thanks for all the great wisdom! Everything works almost perfectly now. One other quick question if you don't mind, though. Is there any prettier syntax than:
%{ $config->acls }->{$_}
to return the value during the foreach loop? Or should I just stick with the while loop if I want pretty code?
Thanks again! | [reply] [d/l] |
|
|
my $loopHashRef = $mod->acls;
foreach (keys %$loopHashRef) {
print $loopHashRef->{$_};
}
If you like, you could also assign the return value directly into a hash and loop over that:
my %loopHash = %{$mod->acls};
foreach (keys %loopHash) {
print $loopHash{$_};
}
Update: Fixed a sigil - *grumble* copy+paste mistakes... *grumble* | [reply] [d/l] [select] |
|
|
my %hash = %{ $config->acls }; # to get a full hash,
# and
my $item = $config->acls->{thatkey}; # to get a single element.
Now the first element is possibly a bit deceiving, because it would work even if the hashref was "converted" to the flattened list of its pairs, whereas the rvalue is a hash at all effects, so that it can directly used e.g. with each and keys, like it was already explained to you.
Whatever, accessing elements as per the second example, still involves method calls, and although I, like so many others, recommend all the time not to bother about alleged optimizations, that feels somewhat unsatisfactory. Personally, I'd just assign to a suitably lexically scoped hash say, %tmp for convenience. YMMV. | [reply] [d/l] [select] |
Re: Hashes as return values
by Sioln (Sexton) on Jan 17, 2006 at 15:56 UTC
|
foreach(keys $mod->acls) {
}
foreach(keys %{$mod->acls}) {
print "$_";
}
| [reply] [d/l] [select] |