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

Discussion in 'Perl Misc' started by Richard Harman, Sep 16, 2005.

  1. 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)}]});
     
    Richard Harman, Sep 16, 2005
    #1
    1. Advertising

  2. Richard Harman

    Eric Bohlman Guest

    Richard Harman <> wrote in
    news:p:

    > 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.
     
    Eric Bohlman, Sep 16, 2005
    #2
    1. Advertising

  3. On Fri, 16 Sep 2005 15:23:08 +0000, Eric Bohlman wrote:

    > Richard Harman <> wrote in
    > news:p:
    >
    >> 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>
     
    Richard Harman, Sep 16, 2005
    #3
  4. Richard Harman

    Paul Lalli Guest

    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
     
    Paul Lalli, Sep 16, 2005
    #4
  5. Richard Harman

    Anno Siegel Guest

    Richard Harman <> wrote in comp.lang.perl.misc:
    > On Fri, 16 Sep 2005 15:23:08 +0000, Eric Bohlman wrote:
    >
    > > Richard Harman <> wrote in
    > > news:p:
    > >
    > >> 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.
     
    Anno Siegel, Sep 20, 2005
    #5
  6. Richard Harman

    Paul Lalli Guest

    Anno Siegel wrote:
    > Richard Harman <> 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
     
    Paul Lalli, Sep 20, 2005
    #6
  7. Richard Harman

    Anno Siegel Guest

    Paul Lalli <> wrote in comp.lang.perl.misc:
    > Anno Siegel wrote:
    > > Richard Harman <> 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.
     
    Anno Siegel, Sep 20, 2005
    #7
  8. Richard Harman

    Anno Siegel Guest

    FAQ suggestion [Was: scalar and hash slices -- is it supposed to work this way?]

    Anno Siegel <-berlin.de> wrote in comp.lang.perl.misc:
    > Paul Lalli <> 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.
     
    Anno Siegel, Sep 24, 2005
    #8
  9. Richard Harman

    Anno Siegel Guest

    FAQ suggestion [Was: scalar and hash slices -- is it supposed to work this way?]

    Anno Siegel <-berlin.de> wrote in comp.lang.perl.misc:
    > Paul Lalli <> 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.
     
    Anno Siegel, Sep 24, 2005
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stephan Aspridis

    Loop doesn't behave the way it's supposed to.

    Stephan Aspridis, Jan 3, 2004, in forum: C Programming
    Replies:
    19
    Views:
    534
    Stephan Aspridis
    Jan 11, 2004
  2. rp
    Replies:
    1
    Views:
    581
    red floyd
    Nov 10, 2011
  3. Clint Olsen
    Replies:
    6
    Views:
    400
    Jeff 'japhy' Pinyan
    Nov 13, 2003
  4. Dinko Korunic

    Multi-dim hash slices

    Dinko Korunic, Jan 17, 2005, in forum: Perl Misc
    Replies:
    2
    Views:
    147
    Tad McClellan
    Jan 18, 2005
  5. Mark

    Replace scalar in another scalar

    Mark, Jan 27, 2005, in forum: Perl Misc
    Replies:
    4
    Views:
    190
    Arndt Jonasson
    Jan 27, 2005
Loading...

Share This Page