Reference found where even-sized list expected in Perl - Possible pass-by-reference error?
Asked Answered
B

4

11

I have a Perl class/module that I created to display Bible verses. In it there is a hash that stores several verses, with the key being the book/chapter/verse and the value being the text. This hash is returned from the module.

I'm including the Bible class in a controller class, and that connection seems to work. The problem is I keep getting errors on executing. My IDE because I'm following a Lynda tutorial, is Eclipse with the EPIC plugin.

The error is:

Reference found where even-sized list expected at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 42.
Use of uninitialized value $value in concatenation (.) or string at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 45.
HASH(0x19ad454)  => 

Here is the CONTROLLER class:

#!/usr/bin/perl
# eh_bibleInspiration_controller.pl by Eric Hepperle - 06/23/13
#

use strict;
use warnings;

use Data::Dumper;
use EHW_BibleInspiration;

main(@ARGV);

sub main
{
    my $o = EHW_BibleInspiration->new; # instantiate new object.
    my %bo_ref = $o->getBibleObj();
    print "\$o is type: " . ref($o) . ".\n";
    print "\%bo_ref is type: " . ref(\%bo_ref) . ".\n";
#    exit;

    $o->getVerseObj();
    listHash(\%bo_ref);

    message("Done.");
}

sub message
{
    my $m = shift or return;
    print("$m\n");
}

sub error
{
    my $e = shift || 'unkown error';
    print("$0: $e\n");
    exit 0;
}

sub listHash
{
    my %hash = @_;
    foreach my $key (sort keys %hash) {
        my $value = $hash{$key};
        message("$key  => $value\n");
    }
}

Here is the class that returns the verses and has the method to pick a random verse:

# EHW_BibleInspiration.pm
#   EHW_BibleInspiration.
#

package EHW_BibleInspiration;
use strict;
use warnings;
use IO::File;
use Data::Dumper;

our $VERSION = "0.1";

sub new
{
    my $class = shift;
    my $self = {};
    bless($self, $class); # turns hash into object
    return $self;
}

sub getVerseObj
{
    my ($self) = @_;

    print "My Bible Verse:\n";
    my $verses = $self->getBibleObj();
    # get random verse
    #$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};

    #  sub mysub {
    #    my $params = shift;
    #    my %paramhash = %$params;
    #  }

#    my %verses = %{$verses};
#    my $random_value = %verses{(keys %verses)[rand keys %verses]};
#    print Dumper(%{$random_value});
}

sub getBibleObj
{
    my ($self) = @_;

    # create bible verse object (ESV)
    my $bibleObj_ref = {
        'john 3:16'         => 'For God so loved the world,that he gave his only Son, that whoever believes in him should not perish but have eternal life.',
        'matt 10:8'         => 'Heal the sick, raise the dead, cleanse lepers, cast out demons. You received without paying; give without pay.',        
        'Luke 6:38'         => 'Give, and it will be given to you. Good measure, pressed down, shaken together, running over, will be put into your lap. For with the measure you use it will be measured back to you.',              
        'John 16:24'        => 'Until now you have asked nothing in my name. Ask, and you will receive, that your joy may be full.',        
        'Psalms 32:7'       => 'You are a hiding place for me; you preserve me from trouble; you surround me with shouts of deliverance. Selah',
        'Proverbs 3:5-6'    => 'Trust in the LORD with all your heart, and do not lean on your own understanding. 6 In all your ways acknowledge him, and he will make straight your paths.',
        'John 14:1'         => 'Let not your hearts be troubled. Believe in God; believe also in me.'
    };

    my $out = "The BIBLE is awesome!\n";

    return $bibleObj_ref;
}

1;

What am I doing wrong? I suspect it has something to do with hash vs hash reference, but I don't know how to fix it. My dereferencing attempts had failed miserably because I don't really know what I'm doing. I modeled my random getter off of something I saw on perlmonks. #$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};

Beanstalk answered 25/6, 2013 at 13:4 Comment(0)
R
10

In the main, you have:

 my %bo_ref = $o->getBibleObj();

but, in package EHW_BibleInspiration;, the method getBibleObj returns : return $bibleObj_ref;

You'd do, in the main : my $bo_ref = $o->getBibleObj();

and then call listHash($bo_ref);

Finaly, don't forget to change sub listHash to:

sub listHash
{
    my ($hash) = @_;
    foreach my $key (sort keys %{$hash}) {
        my $value = $hash->{$key};
        message("$key  => $value\n");
    }
}
Raggedy answered 25/6, 2013 at 13:41 Comment(2)
Sorry, I haven't been able to test this yet. I hope to get to it over the weekend. Thank you for your patience.Beanstalk
Thanks @M42. I was able to implement your changes this morning and now my code works with pass-by-reference, which fixes the issue. I have also modified the title of this post to more accurately reflect the question I asked.Beanstalk
S
7

In your main, you do

listHash(\%bo_ref);

This passes a hash reference to the sub. However, it tries to unpack its arguments like

my %hash = @_;

Oops, it wants a hash.

  1. Either, we pass it a hash: listHash(%bo_ref). This saves us much typing.
  2. Or, we handle the reference inside the sub, like

    sub listHash {
      my ($hashref) = @_;
      foreach my $key (sort keys %$hashref) {
        my $value = $hashref->{$key};
        print "$key  => $value\n";
      }
    }
    

    Notice how the reference uses the dereference arrow -> to access hash entries, and how it is dereferenced to a hash for keys.

Saundra answered 25/6, 2013 at 13:9 Comment(2)
amon: thanks for your quick response. I'm at work now but I'll try to implement your solution tonight and report back with my resultsBeanstalk
That's only half the problem. %bo_ref is assigned a hash ref too.Rectitude
M
1

I suspect that your suspicion is correct. In your method sub listHash you're correctly passing in the hash but you're trying to use a hash instead of a hash reference for the internal variable. Try using my ($hash) = @_; instead of my %hash = @_;.

When using references you can use the -> operator to de-reference it to get to the underlying values. The rest of your method should look like this:

sub listHash
{
    my ($hash) = @_;
    foreach my $key (sort keys %{$hash}) {
        my $value = $hash->{$key};
        message("$key  => $value\n");
    }
}

On line 43 of your program I had to tell Perl that the reference should be a hash reference by calling keys %{$hash}. Then on line 44 I de-referenced the hash to get the correct value by calling $hash->{$key}. For more information on Perl and references you can read the through the tutorial.

Mango answered 25/6, 2013 at 13:13 Comment(0)
F
0

listHash is expecting a hash and you're passing it a hash reference. Change:

listHash(\%bo_ref);

to:

listHash(%bo_ref);
Fordone answered 25/6, 2013 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.