pseudo hash syntax in 5.10

P

Patrick Viet

Hello,

I've been using a weird syntax to assign elements from a hash to array
for several years now. Doesn't work in 5.10. I saw the changelog and it
said pseudo-hashes didn't exist. Didn't know it was pseudo hash I was
using... Anybody knows how to adapt my code ?

Here it is :

$h = {
a => 'data1',
b => 'data2',
c => 'data3',
...
};

my ($data_a,$data_b) = @{$h}{'a','b'};

Any other idea to do this ? Obviously an alternative syntax would be :

my $data_a = $h->{'a'};
my $data_b = $h->{'b'};

But this kind of sucks because my real usage is like this :

(in sql req)
while(my $href = $sth->fetchrow_hashref) {
my $key = join('|',@{$href}{@cols_primary});

Which is really practical ...

Any ideas ?

Thanks,
 
M

Matija Papec

Patrick said:
Hello,

I've been using a weird syntax to assign elements from a hash to array
for several years now. Doesn't work in 5.10. I saw the changelog and it
said pseudo-hashes didn't exist. Didn't know it was pseudo hash I was
using...

You were using hash slice on the regular hash, nothing to worry about.
Here it is :

$h = {
a => 'data1',
b => 'data2',
c => 'data3',
...
};

my ($data_a,$data_b) = @{$h}{'a','b'};

This should also work under 5.10, what kind of error do you get when
reading hash slice?
 
T

Tad J McClellan

Patrick Viet said:
Hello,

I've been using a weird syntax to assign elements from a hash to array
for several years now.


The "weird syntax" looks like a "hash slice" rather than a "pseudo hash"
to me...

Doesn't work in 5.10.


Have you seen the Posting Guidelines that are posted here frequently?

Are you getting an error message?

If so, what is the exact text of the message?

If not, then what does "doesn't work" mean when you say it?

That is, what were you expecting it to do, and what is it doing instead?

I saw the changelog and it
said pseudo-hashes didn't exist. Didn't know it was pseudo hash I was
using...


pseudo-hashes apply only to arrays.

There is only one array in all of the code that you've posted.

Is the 1st element in @cols_primary a reference to a hash?

If not, then there are no pseudo hashes here...

Anybody knows how to adapt my code ?

Here it is :

$h = {
a => 'data1',
b => 'data2',
c => 'data3',
...
};

my ($data_a,$data_b) = @{$h}{'a','b'};


That is a vanilla hash slice.

I don't expect that hash slices were broken in 5.10 (I don't have 5.10 yet).

Any other idea to do this ? Obviously an alternative syntax would be :

my $data_a = $h->{'a'};
my $data_b = $h->{'b'};

But this kind of sucks because my real usage is like this :

(in sql req)
while(my $href = $sth->fetchrow_hashref) {
my $key = join('|',@{$href}{@cols_primary});

Which is really practical ...


You have not shown us the contents of @cols_primary, so we cannot
comment on this piece of code.
 
P

Patrick Viet

Have you seen the Posting Guidelines that are posted here frequently?

No sorry, i'm not a thorough usenet poster, I didn't know there was such
a thing. But that I understand :
Have you seen the Posting Guidelines that are posted here frequently?
Are you getting an error message?
If so, what is the exact text of the message?
If not, then what does "doesn't work" mean when you say it?
That is, what were you expecting it to do, and what is it doing
instead?

So I'll post some more detail.

BTW I got the stuff to work. But I don't understand why it doesn't work
anymore while it did in 5.8 ...

Here is my full test :

--------------------
#!/usr/bin/perl

use warnings;
use strict;

my $h = {
a => 'test1',
b => 'test2',
c => 'test3',
};

my @list = qw(a b);

my ($var1,$var2) = @{%$h}{@list};

print "var1 : $var1 $var2\n";
--------------------

$ ./test
Can't use string ("3/8") as a HASH ref while "strict refs" in use at
../test line 14.

And if I take out the % on the my var1,var2 line, I get what I expected:

$ ./test
var1 : test1 test2

I've solved my problem in the sense that my software can work again, but
I don't understand what that message is, why it stopped working in 5.10,
and where that 3/8 crap comes from (?!)


Other script that produces the same result without hash ref :


--------------------
#!/usr/bin/perl

use warnings;
use strict;

my %h = (
a => 'test1',
b => 'test2',
c => 'test3',
);

my @list = qw(a b);

my ($var1,$var2) = @{\%h}{@list};

print "var1 : $var1 $var2\n";
 
P

Patrick Viet

Have you seen the Posting Guidelines that are posted here frequently?

No sorry, i'm not a thorough usenet poster, I didn't know there was such
a thing. But that I understand :
Have you seen the Posting Guidelines that are posted here frequently?
Are you getting an error message?
If so, what is the exact text of the message?
If not, then what does "doesn't work" mean when you say it?
That is, what were you expecting it to do, and what is it doing
instead?

So I'll post some more detail.

BTW I got the stuff to work. But I don't understand why it doesn't work
anymore while it did in 5.8 ...

Here is my full test :

--------------------
#!/usr/bin/perl

use warnings;
use strict;

my $h = {
a => 'test1',
b => 'test2',
c => 'test3',
};

my @list = qw(a b);

my ($var1,$var2) = @{%$h}{@list};

print "var1 : $var1 $var2\n";
--------------------

$ ./test
Can't use string ("3/8") as a HASH ref while "strict refs" in use at
../test line 14.

And if I take out the % on the my var1,var2 line, I get what I expected:

$ ./test
var1 : test1 test2

I've solved my problem in the sense that my software can work again, but
I don't understand what that message is, why it stopped working in 5.10,
and where that 3/8 crap comes from (?!)


Other script that produces the same result without hash ref :


--------------------
#!/usr/bin/perl

use warnings;
use strict;

my %h = (
a => 'test1',
b => 'test2',
c => 'test3',
);

my @list = qw(a b);

my ($var1,$var2) = @{\%h}{@list};

print "var1 : $var1 $var2\n";
 
G

Gunnar Hjalmarsson

Patrick said:
my ($var1,$var2) = @{%$h}{@list};
-----------------------^

What is that % character supposed to do? It was not there in your
initial post.
 
M

Marc Lucksch

Patrick said:
my @list = qw(a b);

my ($var1,$var2) = @{%$h}{@list};
Well, there is you problem right there, because in your first post you
wrote:
@{$h}{@list}
and said:
@{%$h}{@list};
Which is a different thing. scalar %$h gives you the bucket information
(3/8) in your case, means: 3 of 8 buckets are filled.

Quote man perldata:
If you evaluate a hash in scalar context, it returns false if the hash
is empty. If there are any key/value pairs, it returns true; more
precisely, the value returned is a string consisting of the number of
used buckets and the number of allocated buckets, separated by a
slash. This is pretty much useful only to find out whether Perl's
internal hashing algorithm is performing poorly on your data set. For
example, you stick 10,000 things in a hash, but evaluating %HASH in
scalar context reveals "1/16" , which means only one out of sixteen
buckets has been touched, and presumably contains all 10,000 of your
items. This isn't supposed to happen. If a tied hash is evaluated in
scalar context, a fatal error will result, since this bucket usage
information is currently not available for tied hashes.
--------------------
#!/usr/bin/perl

use warnings;
use strict;

my %h = (
a => 'test1',
b => 'test2',
c => 'test3',
);

my @list = qw(a b);

my ($var1,$var2) = @{\%h}{@list};

You should better do this (no refrences needed):

my ($var1,$var2) = @h{@list};

Simple way to remember this:

$h{a}: Scalar of %h
%h: Hash %h
@h{@ab} = array from %h of the keys in @ab.

Marc "maluku" Lucksch
 
T

Tim McDaniel

You should better do this (no refrences needed):

my ($var1,$var2) = @h{@list};

Note that Marc changed the quoted code but left it quoted and with
Viet's attribution. The original had
my $h = { ... };
but the new version above has
my %h = ( ... );

That is, Marc changed it from a scalar variable that contained a
reference to a hash - to a hash variable that contained, well, a hash.

I agree that that using a hash, instead of a reference to a hash, is
better is in this kind of case. I just wanted to point out that
goalposts were being moved silently.
 
T

Tim McDaniel

less crappy version:
my ($var1,$var2) = @h{@list};

Please test your code before making suggestions. With the original
my $h = {
a => 'test1',
b => 'test2',
c => 'test3',
};
the "less crappy" version (under perl -w and use strict) gives
Global symbol "%h" requires explicit package name at
local/test/051.pl line 15.
Execution of local/test/051.pl aborted due to compilation errors.

As Marc (silently) noted, you have to change the assignment from
$h = {...} to %h = (...).
 
T

Tim McDaniel

Well, there is you problem right there, because in your first post you
wrote:

Which is a different thing. scalar %$h gives you the bucket information
(3/8) in your case, means: 3 of 8 buckets are filled.

To expand on that: in, @{EXPR}{list} (for whatever happens to be
"EXPR" in any particular case), the syntax requires that EXPR be a
reference to a hash, or be the bare name of a hash variable itself.
If EXPR is indeed an expression, like %$h, it is evaluated, so far as
I can tell, in a scalar context. As Marc noted, that gives you a
string that tells you information about the hash table (here, that
there are 3 elements and 8 buckets, I think, but I can't find it
quickly in the man pages).

In Perl 5.10, and I suspect in many earlier versions, you can use
either
@{$h}{@list}
or
@$h{@list}

But, as Marc noted, using a real hash variableis better in this case,
avoiding the extra $ in lots of cases.
 
G

Gunnar Hjalmarsson

Tim said:
But, as Marc noted, using a real hash variableis better in this case,
avoiding the extra $ in lots of cases.

I'm not sure that Marc noted that. Besides, considering that the OP's
real code is:

while(my $href = $sth->fetchrow_hashref) {
my $key = join('|',@{$href}{@cols_primary});

I'm somewhat confused by your advice.
 
M

Marc Lucksch

Gunnar said:
I'm not sure that Marc noted that. Besides, considering that the OP's
real code is:

while(my $href = $sth->fetchrow_hashref) {
my $key = join('|',@{$href}{@cols_primary});
Other script that produces the same result without hash ref :
use warnings;
use strict;

my %h = (
a => 'test1',
b => 'test2',
c => 'test3',
);

my @list = qw(a b);

my ($var1,$var2) = @{\%h}{@list};

print "var1 : $var1 $var2\n";

Marc "Maluku" Lucksch



=begin OffTopic

And about this code:
while(my $href = $sth->fetchrow_hashref) {
my $key = join('|',@{$href}{@cols_primary});

I think the OP wants to build kind of a primary key out of some combined
values of the row. (Just a wild guess)
Any database I know can use combined columns as keys (also primary keys)
so I think that this code is quite useless with a good database design.

=end OffTopic

=cut
 
P

Peter J. Holzer

Please test your code before making suggestions. With the original
my $h = {
a => 'test1',
b => 'test2',
c => 'test3',
};

That isn't the original in this case. It's:

my %h = (
a => 'test1',
b => 'test2',
c => 'test3',
);
As Marc (silently) noted, you have to change the assignment from
$h = {...} to %h = (...).

Patrick already did this in the posting Matija replied to.

hp
 
T

Tad J McClellan

Tim McDaniel said:
If EXPR is indeed an expression, like %$h, it is evaluated, so far as
I can tell, in a scalar context. As Marc noted, that gives you a
string that tells you information about the hash table (here, that
there are 3 elements and 8 buckets, I think, but I can't find it
quickly in the man pages).


It is in the "Scalar values" section of perldata.pod:

If you evaluate a hash in scalar context, it returns false if the
hash is empty. If there are any key/value pairs, it returns true;
more precisely, the value returned is a string consisting of the
number of used buckets and the number of allocated buckets, separated
by a slash.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top