Ahbeyra has asked for the wisdom of the Perl Monks concerning the following question:

In this package, it wont get any values but stats_change...
package item; use strict; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{FILLABLE} = undef; $self->{NAME} = undef; $self->{VAL} = undef; $self->{ATYPE} = undef; $self->{VOL} = undef; $self->{MASS} = undef; $self->{DESC} = undef; $self->{RACE} = undef; $self->{stats_change} = []; bless($self); return $self; } sub name { my $self = shift; if (@_) { $self->{NAME} = shift } return $self->{NAME}; } sub val { my $self = shift; if (@_) { $self->{VAL} = shift } return $self->{VAL}; } sub atype { my $self = shift; if (@_) { $self->{ATYPE} = shift } return $self->{ATYPE}; } sub vol { my $self = shift; if (@_) { $self->{VOL} = shift } return $self->{VOL}; } sub mass { my $self = shift; if (@_) { $self->{MASS} = shift } return $self->{MASS}; } sub desc { my $self = shift; if (@_) { $self->{DESC} = shift } return $self->{DESC}; } sub race { my $self = shift; if (@_) { $self->{RACE} = shift } return $self->{RACE}; } sub immortal { my $self = shift; if (@_) { $self->{IMMORTAL} = shift } return $self->{IMMORTAL}; } sub fillable { my $self = shift; if (@_) { $self->{FILLABLE} = shift } return $self->{FILLABLE}; } sub stats_change { my $self = shift; if (@_) { @{ $self->{stats_change} } = @_ } return @{ $self->{stats_change} }; } 1;
When i dump the values of an example of this, i get...
$VAR1 = bless( { 'DESC' => undef, 'stats_change' => [ 19, 3 ], 'ATYPE' => undef, 'VOL' => undef, 'NAME' => undef, 'VAL' => undef, 'MASS' => undef, 'FILLABLE' => undef, 'RACE' => undef }, 'item' );
Why wont it take the values for the rest of them?

Replies are listed 'Best First'.
Re: OO package problems...
by Chmrr (Vicar) on Oct 23, 2001 at 07:18 UTC

    If you're expecting to be able to pass parameters to the new method (like you do here), you would want to take the parameters that are passed to new and use them as the values for your internal hash:

    sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {FILENAME => undef, NAME => undef, VAL => undef, ATYPE => undef, VOL => undef, MASS => undef, DESC => undef, RACE => undef, stats_change => [], @_}; # <-- Note this line here. # It takes the values passed to new and will override the "defaults" s +et above. bless($self); return $self; }

    Update: It looks like that is what you're trying to do. The reason only stats_change is "working" is because that's the only one you're explicitly setting. Your original new code does not automagically set the other values for you.</code>

    perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^+*`^ ve^#$&V"+@( NO CARRIER'

Re: OO package problems...
by dragonchild (Archbishop) on Oct 23, 2001 at 17:19 UTC
    The other answers have solved your immediate problem. I would like to address a style issue.

    When working with Object Orientation, there are a number of considerations you should take into account in order to get the most out of the OO paradigm. I've noticed that nearly every "OO" implementation does not follow at least one of these.

    1. Encapsulation. You do this by putting the actual data values into their own namespace. This is good. However, you allow anyone to just come in and muck with the data. This is legal OO ... just not good OO.
    2. Inheritance. While you don't show us much of the full class hierarchy, I'm going to assume that you do have a system of classes and use @ISA and the like. However, I immediately note that you don't do things like my $self = SUPER::new(@_);, allowing for a generic constructor. If you ever wanted to change how the objects were implemented from a hash to, say, a closure or parallel lists, you would have to completely rewrite every single class.
    3. Polymorphism. This is where you allow for classes to use their parents' methods. In fact, this is where classes are supposed to use their parents' methods. They are only supposed to override them, or add new methods, if they need to. This is where you get the benefits of code reuse.
    What you should be looking at doing is giving the object (in this case, some sort of magical cloak) its attribute values, then having the object answer questions about itself. Not simple questions like "What is your arrayref of stat modifiers?", but questions like "What is the modification you give for XXX?". This allows for you to change how that is implemented internally, yet not change every piece of code that would use that method.

    Below, I suggest a possible rewrite of this class. This rewrite is dependent on there being a base class of all objects, then a base class of all magical objects. In addition, there should be a class for each of the stats, which would contain things like "How much can this much strength lift?" or "What is the armor modifier for this much Dex?" and the like.

    use 5.6.0; use strict; use warnings; package Item; my @OPTIONS = qw(ATYPE DESC FILLABLE MASS NAME RACE VOL VAL ); use constant STR => (0); use constant DEX => (1); sub new { my $class = shift; # Create a separate copy constructor. return undef if defined $class; my $self = {} bless $self, $class; my %args = @_; foreach my $option (@OPTIONS) { $self->{$option} = $args{$option} || undef; } $self->{STATS_CHANGE} = $args{STATS_CHANGE} || [0,0]; return $self; } sub name { $_[1] ? $_[0]->{NAME} = $_[1] : $_[0]->{NAME} }sub vol { $ +_[1] ? $_[0]->{VOL} = $_[1] : $_[0]->{VOL} } sub val { $_[1] ? $_[0]->{VAL} = $_[1] : $_[0]->{VAL} } sub desc { $_[1] ? $_[0]->{DESC} = $_[1] : $_[0]->{DESC} } sub fillable { $_[0]->{FILLABLE} } sub mass { $_[0]->{MASS} } sub atype { $_[0]->{ATYPE} } sub race { $_[0]->{RACE} } sub stats_change { $_[0]->{STATS_CHANGE}[$_[1]] } 1; __END__
    Note that some of the attributes are now read-only. This is because, I'm assuming, that Armor Type and Race-Allowed shouldn't be changing for the life of an item. Also, FILLABLE and MASS need to be more complex calculations, based on whether or not there's stuff inside this item. Both should be read-only, changing only due to internal considerations, such as how much stuff is in this item.

    stats_change() now takes a attribute (which is defined as a constant), and returns what the stat change is for that specific attribute. In addition, it's read-only. Your previous way was forcing the caller to know about internal implementation. This prevents you from easily changing the implementation of this object.

    Quick note - the use of constants to interface an array is a poor choice, but better than what you were doing. It is better instead to use objects for attribute types and have the item use a Stats::Modifier object which interacts with a Stats object. It sounds like a lot more work, and it is, but it makes your life a lot easier down the road.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Also check out Class::MethodMaker which will automate generating much of this code for you. You just give it a list of attributes and what not and it writes all of the mostly boilerplate code for accessors. You can still write your own custom accessors for things that C::MM can't handle itself.

      And consider getting the excellent book, Object Oriented Perl.

Re: OO package problems...
by Zaxo (Archbishop) on Oct 23, 2001 at 07:29 UTC

    One thing to add to Chmrr's good suggestions. You may want to use 2-argument bless, and just return its value:

    sub new { # As in Chmerrs reply return bless $self, $class; }

    After Compline,
    Zaxo

Re: OO package problems...
by Ahbeyra (Monk) on Oct 23, 2001 at 07:12 UTC
    This is the what the value that should have been dumped was based on. $main::objbase->[11] = sub { my $i = item->new('NAME','brown leather cloak','DESC','About four feet in length, this cloak is designed to help ward against bitter weather as well as provide cover in forested areas. The leather used to craft this cloak has been treated to resist water, allowing its user to stay dry during a serious rainstorm. Comfort has been tossed aside to provide as much protection without compromising weight limits.', 'ATYPE', 'supertorso', 'MASS', '7', 'VOL', '2', 'VAL', '25', 'AC', 5); $i->stats_change(19,3); return($i); };
      Well, the only methods you call in that code are new() and stats_change(), and your new() method simply sets all the values to undef. If you want the new() method to set the values based on the arguments you pass in, you need to code it that way. :)