Can't use undefined value as a HASH reference

Discussion in 'Perl Misc' started by alexbarham@yahoo.ca, Nov 27, 2005.

  1. Guest

    I am working through the Mastering Algorithms with PERL and there is a
    section of code I don't quite honestly understand and it is giving me a
    compile error of "Can't use an undefined value as a HASH reference".
    Here is the code:

    #! /usr/bin/perl -w

    sub intersection
    {
    my($i,$sizei) = (0,scalar keys%{$_[0]});
    my($j,$sizej);

    for($j=1;$j<@_;$j++)
    {
    $sizej = scalar keys %{$_[$j]};
    }
    ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

    my @intersection = keys %{splice @_,$i,1};
    my $set;
    while($set = shift)
    {
    @intersection = grep {exists $set->{$_}} @intersection;
    }

    my %intersection;
    @intersection {@intersection} = ();

    return \%intersection;

    }

    @Cats{qw(cat lion tiger)} = ();
    @Asian{qw(tiger panda yak)} = ();
    @Striped{qw(zebra tiger)} = ();

    @Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

    print join(" ",keys %{$Cats_Asian_Striped}),"\n";

    This should output just tiger (the intersection of all three hashes).
    Can someone please explain the syntax of the line:

    I have two questions about the code:

    1) The following line is where the error is generated:
    my @intersection = keys %{splice @_,$i,1);
    I understand what a splice does but if I understand correctly, @_
    refers to the arguments passed into the subroutine. $i is initialized
    to 0 at the beginning of the script and then gets set to the smallest
    array. This should be @Striped, which is equal to 2. Thus
    splice(@_,2,1) looks to me like it will remove the @Striped from @_??
    How can I fix this to eliminate the error?
    2) What kind of data structure is the following line:
    @Cats{qw(cat lion tiger)} = ();
    It start with an array symbol but the parenthese look like it is
    initialized to zero elements??

    Thank you for your help
    , Nov 27, 2005
    #1
    1. Advertising

  2. Guest

    wrote:
    > I am working through the Mastering Algorithms with PERL and there is a
    > section of code I don't quite honestly understand and it is giving me a
    > compile error of "Can't use an undefined value as a HASH reference".
    > Here is the code:


    This code came directly from Mastering Algorithms, or is it something
    you whipped up yourself?

    >
    > #! /usr/bin/perl -w
    >
    > sub intersection
    > {
    > my($i,$sizei) = (0,scalar keys%{$_[0]});
    > my($j,$sizej);
    >
    > for($j=1;$j<@_;$j++)
    > {
    > $sizej = scalar keys %{$_[$j]};
    > }
    > ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;


    It seems like this last line should be inside the loop, not after
    it.


    > I have two questions about the code:
    >
    > 1) The following line is where the error is generated:
    > my @intersection = keys %{splice @_,$i,1);
    > I understand what a splice does but if I understand correctly, @_
    > refers to the arguments passed into the subroutine. $i is initialized
    > to 0 at the beginning of the script and then gets set to the smallest
    > array. This should be @Striped, which is equal to 2.


    You think $i should be 2. Add a print or a warn statement to see if it
    actually is.

    > 2) What kind of data structure is the following line:
    > @Cats{qw(cat lion tiger)} = ();


    It is a hash slice. See the section on slices in perldoc perldata.

    > It start with an array symbol but the parenthese look like it is
    > initialized to zero elements??



    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Nov 27, 2005
    #2
    1. Advertising

  3. Guest

    wrote:
    > wrote:
    > > I am working through the Mastering Algorithms with PERL and there is a
    > > section of code I don't quite honestly understand and it is giving me a
    > > compile error of "Can't use an undefined value as a HASH reference".
    > > Here is the code:

    >
    > This code came directly from Mastering Algorithms, or is it something
    > you whipped up yourself?
    >
    > >
    > > #! /usr/bin/perl -w
    > >
    > > sub intersection
    > > {
    > > my($i,$sizei) = (0,scalar keys%{$_[0]});
    > > my($j,$sizej);
    > >
    > > for($j=1;$j<@_;$j++)
    > > {
    > > $sizej = scalar keys %{$_[$j]};
    > > }
    > > ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

    >
    > It seems like this last line should be inside the loop, not after
    > it.
    >
    >
    > > I have two questions about the code:
    > >
    > > 1) The following line is where the error is generated:
    > > my @intersection = keys %{splice @_,$i,1);
    > > I understand what a splice does but if I understand correctly, @_
    > > refers to the arguments passed into the subroutine. $i is initialized
    > > to 0 at the beginning of the script and then gets set to the smallest
    > > array. This should be @Striped, which is equal to 2.

    >
    > You think $i should be 2. Add a print or a warn statement to see if it
    > actually is.
    >
    > > 2) What kind of data structure is the following line:
    > > @Cats{qw(cat lion tiger)} = ();

    >
    > It is a hash slice. See the section on slices in perldoc perldata.
    >
    > > It start with an array symbol but the parenthese look like it is
    > > initialized to zero elements??

    >
    >
    > Xho
    >
    > --
    > -------------------- http://NewsReader.Com/ --------------------
    > Usenet Newsgroup Service $9.95/Month 30GB


    Actually this code is directly from Mastering Algorithms with PERL. I
    changed the code to the following:

    #! /usr/bin/perl -w


    sub intersection
    {
    my($i,$sizei) = (0,scalar keys%{$_[0]});
    my($j,$sizej);


    for($j=1;$j<@_;$j++)
    {
    $sizej = scalar keys %{$_[$j]};
    }
    ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

    print $i,"\n";
    my @intersection = keys %{splice @_,$i,1};
    my $set;
    while($set = shift)
    {
    @intersection = grep {exists $set->{$_}} @intersection;

    }


    my %intersection;
    @intersection {@intersection} = ();


    return \%intersection;



    }


    @Cats{qw(cat lion tiger)} = ();
    @Asian{qw(tiger panda yak)} = ();
    @Striped{qw(zebra tiger)} = ();

    @Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

    foreach my $cat(keys %Cats_Asian_Striped){
    print $Cats_Asian_Striped{$cat},"\n";
    }

    print join(" ",keys %{$Cats_Asian_Striped}),"\n";

    The line:

    my @intersection = keys %{splice @_,$i,1};

    still generates the error: "Can't use and undefined value as a HASH
    reference at intersection.pl line 17". The value the print $i,"\n";
    prints is 3. If I change the line to:

    my @intersection = keys %{splice @_,2,1,}; or @intersection = keys
    %{splice @_,1,1};

    The error disappears but the for loop doesn't print anything. However,
    If I add in:

    print scalar @Cats_Asian_Striped;

    I get a 1, which I would imagine means that there is 1 element in the
    array.

    Hopefully that will shed some light on the error.

    Thanks
    , Nov 30, 2005
    #3
  4. Paul Lalli Guest

    wrote:
    > I am working through the Mastering Algorithms with PERL and there is a
    > section of code I don't quite honestly understand and it is giving me a
    > compile error of "Can't use an undefined value as a HASH reference".
    > Here is the code:
    >
    > #! /usr/bin/perl -w
    >
    > sub intersection
    > {
    > my($i,$sizei) = (0,scalar keys%{$_[0]});
    > my($j,$sizej);
    >
    > for($j=1;$j<@_;$j++)
    > {
    > $sizej = scalar keys %{$_[$j]};
    > }
    > ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;


    This line belongs in the loop above. That is the root cause of the
    error you spotted, because...

    > my @intersection = keys %{splice @_,$i,1};


    The way the code is written, $i is assigned to $j after the loop has
    ended, making $i equal to three, which is outside the bounds of @_,
    which causes the splice to return undef.

    > my $set;
    > while($set = shift)
    > {
    > @intersection = grep {exists $set->{$_}} @intersection;
    > }
    >
    > my %intersection;
    > @intersection {@intersection} = ();
    >
    > return \%intersection;
    >
    > }
    >
    > @Cats{qw(cat lion tiger)} = ();
    > @Asian{qw(tiger panda yak)} = ();
    > @Striped{qw(zebra tiger)} = ();
    >
    > @Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);


    This line is also incorrect. intersection() returns a hash reference.
    Its return value should be assigned to a scalar variable,
    $Cats_Asian_Striped, not an array variable

    > print join(" ",keys %{$Cats_Asian_Striped}),"\n";


    Without that fix, you would likely get another "can't use uninitialized
    variable as HASH ref" here as well. (If the author had used strict, he
    would have spotted this error immediately...)

    > This should output just tiger (the intersection of all three hashes).
    > Can someone please explain the syntax of the line:


    What line?

    > I have two questions about the code:
    >
    > 1) The following line is where the error is generated:
    > my @intersection = keys %{splice @_,$i,1);
    > I understand what a splice does but if I understand correctly, @_
    > refers to the arguments passed into the subroutine. $i is initialized
    > to 0 at the beginning of the script and then gets set to the smallest
    > array.


    No, it gets set to the *index* of the smallest hash. Or at least, it
    *will*, once you fix the code by putting that assignment of $i and
    $isize back into the for loop where it belongs.

    > This should be @Striped


    %Striped. It's a hash, not an array.

    >, which is equal to 2. Thus
    > splice(@_,2,1) looks to me like it will remove the @Striped from @_??


    Yes, but that's only half the point. In addition to removing elements
    from the array, splice also *returns* the elements it removes.
    Therefore, the %{ } syntax surrounding the splice call will dereference
    the hashref that splice removes.

    The hash is removed so that when the while loop iterates through @_
    later (shift operates on @_ by default), it will not try to reprocess
    this hash.

    > How can I fix this to eliminate the error?


    See above.

    > 2) What kind of data structure is the following line:
    > @Cats{qw(cat lion tiger)} = ();
    > It start with an array symbol but the parenthese look like it is
    > initialized to zero elements??


    It is a hash slice. Much like you refer to a single element of a hash
    %Cats like:
    $Cats{'cat'}
    you can refer to several elements of the hash as:
    @Cats{'cat', 'lion', 'tiger'};

    This is a bizarre way of intializing several keys of a hash all to the
    value of undef. It would, in my opinion, be more clearly written:
    my %Cats;
    $Cats{$_} = undef for qw/cat lion tiger/;

    > Thank you for your help


    You're welcome.

    Paul Lalli
    Paul Lalli, Nov 30, 2005
    #4
  5. Guest

    Paul Lalli wrote:
    > wrote:
    > > I am working through the Mastering Algorithms with PERL and there is a
    > > section of code I don't quite honestly understand and it is giving me a
    > > compile error of "Can't use an undefined value as a HASH reference".
    > > Here is the code:
    > >
    > > #! /usr/bin/perl -w
    > >
    > > sub intersection
    > > {
    > > my($i,$sizei) = (0,scalar keys%{$_[0]});
    > > my($j,$sizej);
    > >
    > > for($j=1;$j<@_;$j++)
    > > {
    > > $sizej = scalar keys %{$_[$j]};
    > > }
    > > ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

    >
    > This line belongs in the loop above. That is the root cause of the
    > error you spotted, because...
    >
    > > my @intersection = keys %{splice @_,$i,1};

    >
    > The way the code is written, $i is assigned to $j after the loop has
    > ended, making $i equal to three, which is outside the bounds of @_,
    > which causes the splice to return undef.
    >
    > > my $set;
    > > while($set = shift)
    > > {
    > > @intersection = grep {exists $set->{$_}} @intersection;
    > > }
    > >
    > > my %intersection;
    > > @intersection {@intersection} = ();
    > >
    > > return \%intersection;
    > >
    > > }
    > >
    > > @Cats{qw(cat lion tiger)} = ();
    > > @Asian{qw(tiger panda yak)} = ();
    > > @Striped{qw(zebra tiger)} = ();
    > >
    > > @Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

    >
    > This line is also incorrect. intersection() returns a hash reference.
    > Its return value should be assigned to a scalar variable,
    > $Cats_Asian_Striped, not an array variable
    >
    > > print join(" ",keys %{$Cats_Asian_Striped}),"\n";

    >
    > Without that fix, you would likely get another "can't use uninitialized
    > variable as HASH ref" here as well. (If the author had used strict, he
    > would have spotted this error immediately...)
    >
    > > This should output just tiger (the intersection of all three hashes).
    > > Can someone please explain the syntax of the line:

    >
    > What line?
    >
    > > I have two questions about the code:
    > >
    > > 1) The following line is where the error is generated:
    > > my @intersection = keys %{splice @_,$i,1);
    > > I understand what a splice does but if I understand correctly, @_
    > > refers to the arguments passed into the subroutine. $i is initialized
    > > to 0 at the beginning of the script and then gets set to the smallest
    > > array.

    >
    > No, it gets set to the *index* of the smallest hash. Or at least, it
    > *will*, once you fix the code by putting that assignment of $i and
    > $isize back into the for loop where it belongs.
    >
    > > This should be @Striped

    >
    > %Striped. It's a hash, not an array.
    >
    > >, which is equal to 2. Thus
    > > splice(@_,2,1) looks to me like it will remove the @Striped from @_??

    >
    > Yes, but that's only half the point. In addition to removing elements
    > from the array, splice also *returns* the elements it removes.
    > Therefore, the %{ } syntax surrounding the splice call will dereference
    > the hashref that splice removes.
    >
    > The hash is removed so that when the while loop iterates through @_
    > later (shift operates on @_ by default), it will not try to reprocess
    > this hash.
    >
    > > How can I fix this to eliminate the error?

    >
    > See above.
    >
    > > 2) What kind of data structure is the following line:
    > > @Cats{qw(cat lion tiger)} = ();
    > > It start with an array symbol but the parenthese look like it is
    > > initialized to zero elements??

    >
    > It is a hash slice. Much like you refer to a single element of a hash
    > %Cats like:
    > $Cats{'cat'}
    > you can refer to several elements of the hash as:
    > @Cats{'cat', 'lion', 'tiger'};
    >
    > This is a bizarre way of intializing several keys of a hash all to the
    > value of undef. It would, in my opinion, be more clearly written:
    > my %Cats;
    > $Cats{$_} = undef for qw/cat lion tiger/;
    >
    > > Thank you for your help

    >
    > You're welcome.
    >
    > Paul Lalli


    Thank you very much for your help. The script now runs as expected.
    Here is the revised code:
    #! /usr/bin/perl -w

    sub intersection
    {
    my($i,$sizei) = (0,scalar keys%{$_[0]});
    my($j,$sizej);


    for($j=1;$j<@_;$j++)
    {
    $sizej = scalar keys %{$_[$j]};
    ($i,$sizei) = ($j,$sizej) if $sizej < $sizei;
    }

    print $i,"\n";
    print $j,"\n";
    my @intersection = keys %{splice @_,$i,1};
    print join(" ",@intersection);
    print " ";
    my $set;
    while($set = shift)
    {
    @intersection = grep {exists $set->{$_}} @intersection;

    }

    print join(" ",@intersection);
    my %intersection;
    @intersection {@intersection} = ();


    return \%intersection;



    }


    @Cats{qw(cat lion tiger)} = ();
    @Asian{qw(tiger panda yak)} = ();
    @Striped{qw(zebra tiger)} = ();

    $Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

    print "\n";
    print "Intersection of three sets is: ",keys
    %{$Cats_Asian_Striped},"\n";

    The last line prints "Intersection of three sets is: tiger". As tiger
    can be found in all three arrays. It looks like I had some issues in
    understanding hash slices.

    Thanks again
    , Nov 30, 2005
    #5
    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. rp
    Replies:
    1
    Views:
    499
    red floyd
    Nov 10, 2011
  2. Greg Hauptmann
    Replies:
    8
    Views:
    87
    Robert Klemme
    Jan 13, 2009
  3. Replies:
    2
    Views:
    240
    Gunnar Hjalmarsson
    Feb 26, 2006
  4. Replies:
    0
    Views:
    129
  5. JimJx
    Replies:
    6
    Views:
    874
    John W. Krahn
    Sep 12, 2007
Loading...

Share This Page