views:

77

answers:

1

I'm not sure why perl isn't recognizing the Heap's method add. Getting message given in question title. Here are the most relevant files.

#!/usr/bin/perl -w

use strict;
use Util;
use Heap;
use HuffTree;

my $heap = Heap->new;
my $test = 3;
$heap->add($test); # <--------ERROR HERE-----------

package Heap;

use strict;
use warnings;

use POSIX ();

sub new {
  my $class = shift;
  my $self = { "aref" => [""],
           "next" => 1,
           @_};
  bless $self, $class;
}


sub print {
  my $self = shift;
  my $next = $self->{"next"};
  my $aref = $self->{"aref"};
  print "array => @$aref\n";
  print "next => $next\n";
}


sub compare {
  my ($self, $i, $j) = @_;
  my $x = $self->{"aref"}[$i];
  my $y = $self->{"aref"}[$j];

  if (!defined $x) {
    if (!defined $y) {
      return 0;
    } else {
      return -1;
    }
  }
  return 1 if !defined $y;
  return $x->priority <=> $y->priority;
}


sub swap {
  my ($self, $i, $j) = @_;
  my $aref = $self->{"aref"};
  ($aref->[$i], $aref->[$j]) = ($aref->[$j], $aref->[$i]);
}


sub add {
  my ($self, $value) = @_;
  my $i = $self->{"next"};
  $self->{"aref"}[$i] = $value;

  while ($i > 1) {
    my $parent = POSIX::floor($i/2);
    last if $self->compare($i, $parent) <= 0;
    $self->swap($i, $parent);
    $i = $parent;
  }
  $self->{"next"}++;
}


sub reheapify {
  my ($self, $i) = @_;
  my $left = 2 * $i;
  my $right = 2 * $i + 1;

  my $winleft = $self->compare($i, $left) >= 0;
  my $winright = $self->compare($i, $right) >= 0;
  return if $winleft and $winright;

  if ($self->compare ($left, $right) > 0) {
    $self->swap($i, $left);
    $self->reheapify($left);
  } else {
    $self->swap($i, $right);
    $self->reheapify($right);
  }
}


sub remove {
  my $self = shift;
  my $aref = $self->{"aref"};

  my $result = $aref->[1];
  $aref->[1] = pop @$aref;
  $self->{"next"}--;

  $self->reheapify(1);
  return $result;
}


sub empty {
  my $self = shift;
  return $self->{"next"} == 1;
}

1;

package HuffTree;

    use warnings;
    use strict;

use Pair;
our @ISA = "Pair";


sub priority {
  my $self = shift;

  # lowest count highest priority
  return -$self->{frequency}; 
}


sub left {
  my $self = shift;
  return $self->{left};
}


sub right {
  my $self = shift;
  return $self->{right};
}

1;

package Pair;

use warnings;
use strict;

sub new {
  my $class = shift;
  my $self = { @_ };
  bless $self, $class;
}


sub letter {
  my $self = shift;
  return $self->{letter};
}


sub frequency {
  my $self = shift;
  return $self->{frequency};
}


sub priority {
  my $self = shift;
  return $self->{frequency};
}

1;

package Util;

use strict;
use warnings;

sub croak { die "$0: @_: $!\n"; }


sub load_arg_file {
  my $path_name = shift @ARGV;
  my $fh;
  open($fh, $path_name) || croak "File not found.\n";
  return $fh;
}

1;
+4  A: 

You have a Heap.pm installed from CPAN. That's what gets loaded, not your own Heap.pm. The new sub in the Heap.pm from CPAN looks like this:

sub new {
    use Heap::Fibonacci;

    return &Heap::Fibonacci::new;
}

Which is actually a bug in said module, because Heap::Fibonacci uses the standard bless \$h, $class; thing in its new sub, so the reference is blessed into the Heap package, which does indeed not have a sub called add (Heap::Fibonacci does).

To solve your immediate problem, you can:

  • make sure that your module is picked up before the "other" Heap (by modifying @INC with use lib, for example;
  • or not reinvent the wheel and actually use Heap::Fibonacci).

At any rate, it might be a good idea to report this problem to the Heap module author - because even if you did not have your own Heap.pm, your code would still fail with the same message.

Grrrr
The first solution offered should be "if you want to reinvent the wheel, namespace your wheels so they don't conflict with CPAN". `Heap` should be `ApplicationName::Heap` or `OrganizationName::Heap` or something of the sort. :)
hobbs
Also see [this question about private module names](http://stackoverflow.com/questions/658955/how-do-i-choose-a-package-name-for-a-custom-perl-module-that-does-not-collide).
cjm
Thanks! Makes sense now. @reinventing the wheel, I'm learning Perl so just wanted to try some stuff out.
floogads
+1 great detective work!
Philip Potter