Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > scalar and hash slices -- is it supposed to work this way?

Reply
Thread Tools

scalar and hash slices -- is it supposed to work this way?

 
 
Richard Harman
Guest
Posts: n/a
 
      09-16-2005
I think I found a bug in perl when dealing with hash slices. For some
reason, scalar is interpreting the returned list from a hash slice as a
'scalar comma expression' and is returning the final element (perldoc -f
scalar, 3rd paragraph). Is this the way it's supposed to work? (If this
is not the correct place to ask, where do I go?)

# data
my %hash = ( first=>["Studly","Caps"], second=>["Make","Things","Readable"]);
my $hashref = \%hash;

# slicing the hashref for values (the arrays)
my @array_refs = @$hashref{qw(first second)};

# print out the memory addresses
printf "Contents of hash:\n";
foreach my $key (keys %hash) { print "$key => $hash{$key}\n"; };

printf("Scalar array_refs: %s\n",scalar @array_refs);

# now why doesn't this return 2? A slice is just a list, right?
printf("Scalar hashref slice WRONG: %s\n",scalar @$hashref{qw(first second)});

# but this works (forced list interpolation)
printf("Scalar hashref forced list interpolation RIGHT: %s\n",
scalar @{[@$hashref{qw(first second)}]});

 
Reply With Quote
 
 
 
 
Eric Bohlman
Guest
Posts: n/a
 
      09-16-2005
Richard Harman <(E-Mail Removed)> wrote in
news(E-Mail Removed):

> I think I found a bug in perl when dealing with hash slices. For some


May people have thought they found bugs in perl. Few of them really
have.

> reason, scalar is interpreting the returned list from a hash slice as
> a 'scalar comma expression' and is returning the final element
> (perldoc -f scalar, 3rd paragraph). Is this the way it's supposed to
> work? (If this is not the correct place to ask, where do I go?)


Yes, it's the way it's supposed to work. The entry "What is the
difference between a list and an array?" in perlfaq4 is a good place to
start.

> # data
> my %hash = ( first=>["Studly","Caps"],
> second=>["Make","Things","Readable"]); my $hashref = \%hash;
>
> # slicing the hashref for values (the arrays)
> my @array_refs = @$hashref{qw(first second)};
>
> # print out the memory addresses
> printf "Contents of hash:\n";
> foreach my $key (keys %hash) { print "$key => $hash{$key}\n"; };
>
> printf("Scalar array_refs: %s\n",scalar @array_refs);


@array_refs is an array, and so when put in scalar context evaluates to
the number of elements. That's a property of *arrays* in particular.
>
> # now why doesn't this return 2? A slice is just a list, right?
> printf("Scalar hashref slice WRONG: %s\n",scalar @$hashref{qw(first
> second)});


Your slice is indeed a list, but it's not an array, so it doesn't have
that particular (peculiar?) property.

> # but this works (forced list interpolation)
> printf("Scalar hashref forced list interpolation RIGHT: %s\n",
> scalar @{[@$hashref{qw(first second)}]});


You've actually created an array here.
 
Reply With Quote
 
 
 
 
Richard Harman
Guest
Posts: n/a
 
      09-16-2005
On Fri, 16 Sep 2005 15:23:08 +0000, Eric Bohlman wrote:

> Richard Harman <(E-Mail Removed)> wrote in
> news(E-Mail Removed):
>
>> I think I found a bug in perl when dealing with hash slices. For some

>
> May people have thought they found bugs in perl. Few of them really
> have.


I suspected as much

>> reason, scalar is interpreting the returned list from a hash slice as
>> a 'scalar comma expression' and is returning the final element
>> (perldoc -f scalar, 3rd paragraph). Is this the way it's supposed to
>> work? (If this is not the correct place to ask, where do I go?)

>
> Yes, it's the way it's supposed to work. The entry "What is the
> difference between a list and an array?" in perlfaq4 is a good place to
> start.


Wow, according to perlfaq4 I'm doing all sorts of bad things, like
($exits) = grep { m/pattern/ } @array;

I really should read perlfaqX more often. One would think reading the
various ORA books would glean such information. Although, what I was
trying to "efficiently" do has turned out to be inefficient, so I think I
get to chuck this thought process entirely Thanks for the pointer to
perlfaq4.


<snip>
 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      09-16-2005
Richard Harman wrote:
> I think I found a bug in perl


I should caution you that that statement can be, and perhaps has been,
seen as exceedingly arrogant. Do you really suspect that with the
multitude of people around the world using Perl, that *you* are the
first person to discover a bug?

> when dealing with hash slices. For some
> reason, scalar is interpreting the returned list from a hash slice as a
> 'scalar comma expression' and is returning the final element (perldoc -f
> scalar, 3rd paragraph). Is this the way it's supposed to work? (If this
> is not the correct place to ask, where do I go?)


I don't understand your question. Yes, a "list" in scalar context
returns the last element of that list. Where is the contradiction?

> # data
> my %hash = ( first=>["Studly","Caps"], second=>["Make","Things","Readable"]);
> my $hashref = \%hash;
>
> # slicing the hashref for values (the arrays)
> my @array_refs = @$hashref{qw(first second)};
>
> # print out the memory addresses
> printf "Contents of hash:\n";
> foreach my $key (keys %hash) { print "$key => $hash{$key}\n"; };
>
> printf("Scalar array_refs: %s\n",scalar @array_refs);
>
> # now why doesn't this return 2? A slice is just a list, right?
> printf("Scalar hashref slice WRONG: %s\n",scalar @$hashref{qw(first second)});


Why *would* it return 2? A slice is indeed, a list. A list in scalar
context returns the last element of that list. An *array* in scalar
context, on the other hand, returns the size of that array.

perldoc -q "list and an array"

> # but this works (forced list interpolation)
> printf("Scalar hashref forced list interpolation RIGHT: %s\n",
> scalar @{[@$hashref{qw(first second)}]});


Here you've taken the hash slice (a list), and used it to populate an
anonymous array reference, then dereferenced that reference. The
result is an actual array. An array in scalar context returns its
size.

Paul Lalli

 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      09-20-2005
Richard Harman <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> On Fri, 16 Sep 2005 15:23:08 +0000, Eric Bohlman wrote:
>
> > Richard Harman <(E-Mail Removed)> wrote in
> > news(E-Mail Removed):
> >
> >> I think I found a bug in perl when dealing with hash slices. For some

> >
> > May people have thought they found bugs in perl. Few of them really
> > have.

>
> I suspected as much
>
> >> reason, scalar is interpreting the returned list from a hash slice as
> >> a 'scalar comma expression' and is returning the final element
> >> (perldoc -f scalar, 3rd paragraph). Is this the way it's supposed to
> >> work? (If this is not the correct place to ask, where do I go?)

> >
> > Yes, it's the way it's supposed to work. The entry "What is the
> > difference between a list and an array?" in perlfaq4 is a good place to
> > start.

>
> Wow, according to perlfaq4 I'm doing all sorts of bad things, like
> ($exits) = grep { m/pattern/ } @array;


What do you think is wrong with that? It's a perfectly good idiom
to retrieve the first element of @array for which /pattern/ matches.
I use it all the time (unless I'm using List::Util::first).

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      09-20-2005
Anno Siegel wrote:
> Richard Harman <(E-Mail Removed)> wrote in comp.lang.perl.misc:


> > Wow, according to perlfaq4 I'm doing all sorts of bad things, like
> > ($exits) = grep { m/pattern/ } @array;

>
> What do you think is wrong with that? It's a perfectly good idiom
> to retrieve the first element of @array for which /pattern/ matches.
> I use it all the time (unless I'm using List::Util::first).


What's wrong with it is that the FAQ (which the regulars love to point
the newbies to) specifically says not to use it:

perldoc -q contain
<...>
Please do not use

($is_there) = grep $_ eq $whatever, @array;

or worse yet

($is_there) = grep /$whatever/, @array;

These are slow (checks every element even if the first
matches), inefficient (same reason), and potentially buggy
(what if there are regex characters in $whatever?).

Now maybe this particular FAQ is too paranoid or restrictive, or
problematic in other ways. But I really don't think we can have it
both ways - we can't be both chiding people for not looking at the FAQ
or following the FAQ's responses, and then telling them that there's
nothing wrong with something the FAQ says not to do.

Perhaps this particular FAQ could stand some scrutiny?

Paul Lalli

 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      09-20-2005
Paul Lalli <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> Anno Siegel wrote:
> > Richard Harman <(E-Mail Removed)> wrote in comp.lang.perl.misc:

>
> > > Wow, according to perlfaq4 I'm doing all sorts of bad things, like
> > > ($exits) = grep { m/pattern/ } @array;

> >
> > What do you think is wrong with that? It's a perfectly good idiom
> > to retrieve the first element of @array for which /pattern/ matches.
> > I use it all the time (unless I'm using List::Util::first).

>
> What's wrong with it is that the FAQ (which the regulars love to point
> the newbies to) specifically says not to use it:
>
> perldoc -q contain
> <...>
> Please do not use
>
> ($is_there) = grep $_ eq $whatever, @array;
>
> or worse yet
>
> ($is_there) = grep /$whatever/, @array;
>
> These are slow (checks every element even if the first
> matches), inefficient (same reason), and potentially buggy
> (what if there are regex characters in $whatever?).
>
> Now maybe this particular FAQ is too paranoid or restrictive, or
> problematic in other ways. But I really don't think we can have it
> both ways - we can't be both chiding people for not looking at the FAQ
> or following the FAQ's responses, and then telling them that there's
> nothing wrong with something the FAQ says not to do.
>
> Perhaps this particular FAQ could stand some scrutiny?


I think it could. While it is true that grep for a single element
can be inefficient, whether that is a real concern depends on a lot
of circumstances. Both methods are linear in the length of the list,
what factor you get depends on the statistics of the match. The
grep method may well be adequate.

The argument about $whatever containing regex characters is absolutely
besides the point. If it where valid, there ought to be a warning
against interpolating strings in a regex, ever.

It also ought to mention List::Util::first, which wasn't around when
the answer was written. I'll see what I can do.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      09-24-2005
Anno Siegel <(E-Mail Removed)-berlin.de> wrote in comp.lang.perl.misc:
> Paul Lalli <(E-Mail Removed)> wrote in comp.lang.perl.misc:


[FAQ How can I tell whether a certain element is contained in a list or
array?]

> > Perhaps this particular FAQ could stand some scrutiny?

>
> I think it could.


....or rather, some of it doesn't stand up to scrutiny.

Let's see if "FAQ" in the subject draws brian's attention. Otherwise
I'll jump in when it comes up regularly.

The FAQ in question is found through "perldoc -q contain". The first
part shows how to use hashes, arrays and bit vectors for the purpose,
nothing to change there. Then it goes on

Please do not use

($is_there) = grep $_ eq $whatever, @array;

or worse yet

($is_there) = grep /$whatever/, @array;

These are slow (checks every element even if the first matches), inef-
ficient (same reason), and potentially buggy (what if there are regex
characters in $whatever?). If you're only testing once, then use:

$is_there = 0;
foreach $elt (@array) {
if ($elt eq $elt_to_find) {
$is_there = 1;
last;
}
}
if ($is_there) { ... }

That part I'd replace with

These methods guarantee fast individual tests but require a re-organization
of the original list or array. They only pay off if you have to test
multiple values against the same array.

If you are testing only once, the standard module List::Util exports
the function C<first> for this purpose. It works like

sub first (&@) {
my $code = shift;
foreach (@_) {
return $_ if &{$code}();
}
undef;
}

but has a fast implementation in C.

If speed is of little concern, the common idiom is

($is_there) = grep $_ eq $whatever, @array;

It is slow (checks every element even if the first matches), but simple and
flexible. The variant

($first, @others) = grep $_ eq $whatever, @array;

allows to tell whether the match was unique.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      09-24-2005
Anno Siegel <(E-Mail Removed)-berlin.de> wrote in comp.lang.perl.misc:
> Paul Lalli <(E-Mail Removed)> wrote in comp.lang.perl.misc:


[FAQ How can I tell whether a certain element is contained in a list or
array?]

> > Perhaps this particular FAQ could stand some scrutiny?

>
> I think it could.


....or rather, some of it doesn't stand up to scrutiny.

The FAQ in question is found through "perldoc -q contain". The first
part shows how to use hashes, arrays and bit vectors for the purpose,
nothing to change there. Then it goes on

Please do not use

($is_there) = grep $_ eq $whatever, @array;

or worse yet

($is_there) = grep /$whatever/, @array;

These are slow (checks every element even if the first matches), inef-
ficient (same reason), and potentially buggy (what if there are regex
characters in $whatever?). If you're only testing once, then use:

$is_there = 0;
foreach $elt (@array) {
if ($elt eq $elt_to_find) {
$is_there = 1;
last;
}
}
if ($is_there) { ... }

That part I'd replace with

These methods guarantee fast individual tests but require a re-organization
of the original list or array. They only pay off if you have to test
multiple values against the same array.

If you are testing only once, the standard module List::Util exports
the function C<first> for this purpose. It works like

sub first (&@) {
my $code = shift;
foreach (@_) {
return $_ if &{$code}();
}
undef;
}

but has a fast implementation in C.

If speed is of little concern, the common idiom is

($is_there) = grep $_ eq $whatever, @array;

It is slow (checks every element even if the first matches), but simple and
flexible. The variant

($first, @others) = grep $_ eq $whatever, @array;

allows to tell whether the match was unique.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
Replace scalar in another scalar Mark Perl Misc 4 01-27-2005 02:48 PM
Multi-dim hash slices Dinko Korunic Perl Misc 2 01-18-2005 04:41 AM
Hash slices Gyruss Perl Misc 1 10-25-2004 01:01 PM
Shorthand for($scalar) loops and resetting pos($scalar) Clint Olsen Perl Misc 6 11-13-2003 12:50 AM



Advertisments