I wrote the following module but am not sure how to refer to the "last" and "head" nodes. As well as storing the address of the next node in "{nextNode}" in the previous node.
I am trying to save the reference of the class when storing it but later it's complaining: "Not a HASH reference at List.pm"; which I understand why but am not sure how the syntax would be.
If I de-reference $head and $last ($$last->{nextNode} = \$class) then I think it's using the actual name of my class; List and not the previous object like I want to.
package List;
my $head = undef;
my $last = undef;
sub new {
my $class = shift;
# init the head of the list
if ($head == undef) {
$head = \$class;
print "updated head to:$head", "\n";
}
$last = \$class;
$last->{nextNode} = \$class; # update previous node to point on this new one
print "updated last to:$last", "\n";
my $self = {};
$self->{value} = shift;
$self->{nextNode} = ""; # reset next to nothing since this node is last
return bless $self, $class;
}
Thanks guys
You should be storing $self
everywhere instead of \$class
. Storing $class is simply storing the name of the class, not the object itself.
Also, for $self->{nextNode}
I'd store an undef
instead of a blank string. Or better yet, simply don't create it at all and use exists
when checking if it is there.
You're over thinking it. If you use an array for your list instead of a hash, you don't need to worry about the head and last. The head of an array is $array[0]
and the last member is $array[-1]
. Simple and easy to do.
Here's a quick standard class definition for defining a list. I've only defined a constructor (the new subroutine) and one method (the list).
package Local::List;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
$self->list([]);
}
sub list {
my $self = shift;
my $list_ref = shift;
if (ref $list_ref ne "ARRAY) {
return;
}
if (defined $list_ref) {
$self->{LIST} = $list_ref;
}
if wantarray {
return $self->{LIST};
}
}
The first thing: Use the same standard names everyone else uses. Use new
for the constructor. When I try to look at the documentation on how to use your class, I can search for the word new and know that's how I create a class object. Also, use the variable names $class
and $self
. That's what everyone else does, so it's easy to know what's going on.
Notice in my new
subroutine, the first item passed is the name of the class while the first item passed to my other subroutines is a reference to my class object (i.e. $self
). That's probably the hardest thing to understand about classes.
Notice in new
, I immediately create my $self
and bless it. That way, I can call my other subroutines (my methods) to do the setting for me. This way, my constructor doesn't know how my class is structured. This has a lot of advantages:
Notice that the list
subroutine (or method) can either set a list or return a list. It's much easier if you use the same subroutine to set or get the value. Also in your method subroutines, use a blank return when your method function returns an error. Otherwise, always return something. That makes it easy to test to see if a method failed or not.
Let's look at some of the other methods you probably want to have. Let's have all the four standard list functions:
Here's an example:
sub push {
my $self = shift;
my $member = shift;
if (not defined $member) {
return;
}
my $list_ref = $self->list;
my $return = push @{ $list_ref }, $member;
$self->list($list_ref);
return $return;
}
Wow, that's simple. Notice that the pop
doesn't know what my class looks like. It used the list
method to retrieve a list reference. Then it used the builtin push
method to push a member onto the list. I save that return value, and that's what I'll return. I'm not even sure what push
returns. All I know is that push returns something if it succeeds. (Yes, I know it returns the number of items in the list).
The other three functions are more or less the same. Here's a few more:
All you need to do for current is to store the current value. Use the same function to set and get the value. Notice that my list
method or my push
method, or my new
constructor knows or care how you store it. Nor, do our next
and previous
methods. All they need to do is increment or decrement the value of current
and store it back using the current
method subroutine:
sub next {
my $self = shift
my @list = $self->list; #Returns a list;
my $current = $self->current;
my $list_size = $#list;
if ($current eq $list_size) {
return; #Can't return a value after the end of the list!
}
$current++; #Increment the value;
my $value = $list[$current]; #I'll return this
$self->current($current) #Store the new current
return $value;
}
And, now to the basis of your question: Getting the last and head values of the list. Here's last
sub last {
my $self = shift;
my $list_ref = $self->list;
return ${ $list_ref }[-1];
}
And a quick copy and paste will give me head:
sub head {
my $self = shift;
my $list_ref = $self->list;
return ${ $list_ref }[0];
}
That's it! All that worrying you were doing was for naught.
Sorry for the long post. I just wanted to emphasize that object oriented programming in Perl isn't that tricky as long as you follow a few simple guide lines.
(Simple? What about use Moose;
No, I said simple!). ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With