in reply to My first stab at OO perl...

Looks like a good first stab to me. Biggest gripe i have is with the constructors, and it is not ironic that you would use a variable named $cargocult ;) - try this instead:
sub new { my $class = shift; my $id = shift; my $self = { _ID => $id, _FINALIZED => 0, _EXPENSES => [], _TOTAL => undef, _COUNT => undef, }; return bless $self, $class; }
Get rid of that 'ref (proto)' malarky and note that $id will already be undef if it is not specified. Other than that, everything seems OK - i do have a list of minor nitpicks though: Having said all of that, you should now take a look at CPAN modules like Class::Struct and Class::MethodMaker. I think these modules will help you design your classes by giving you an interface to work with. Also - use POD! This is a must for any class. Include a section with sample usage.

Over all, very good work. And good luck with the next step. :)

jeffa

L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)

Replies are listed 'Best First'.
Re: (jeffa) Re: My first stab at OO perl...
by Theseus (Pilgrim) on Jul 16, 2002 at 17:09 UTC
    Maybe I just don't understand WHY the ref($cargocult) idea is so bad. To me, it makes perfect sense... If someone calls the constructor on an instance rather than the class, it forces it to act as if it were called on the class. Isn't this "correct" in most cases?

    I tried putting the line you tried and then calling my constructor on an already running instance, and it does return an object, but one blessed incorrectly(read: differently) for my purposes. When I try and invoke any methods on this object that is blessed into "Expense=HASH(0x123456)" and not "Expense" it gives me an error.

    So, basically, my question is this... Can you please give me a real world scenario or two where I would want to call $object->new and not CLASS->new, and then an example of how you use that new returned object's methods, since it is not blessed into the correct class? Here's the code I used to come to these conclusions:

      Calling an instance constructor? Yuck! If you want to clone an object, use the right tool, such as Clone:
      use strict; use Clone qw(clone); my $foo = foo->new(5); my $bar = clone($foo); print $bar->id(), "\n"; package foo; use strict; sub new { my ($class,$id) = @_; my $self = { id => $id || 42, }; return bless $self,$class; } sub id { my ($self,$id) = @_; return $self->{id} unless $id; $self->{id} = $id; }
      or provide your own clone() method for the class. I really recommend that you read TheDamian's excellent book, Object Oriented Perl, by the way.

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
        So you agree that calling instance constructors is a bad thing, but you don't agree that inserting code to prevent it from being done(or at least return the same result as if it had been done correctly) is a good thing? That's exactly what I don't understand.

        I personally would never call $newobject = $oldobject->new, but I can't say that nobody who uses a class I design won't, and I want to account for that.

        I'd like to hear your thoughts on the subject(and I'd love to hear merlyn's, if he sees this thread).

        Although you should know that Damian uses ref($caller) extensively in his book (see all the CD::Music examples). I'm not saying that's right, but it makes the context of the recommendation to read the book sound sort of self-contradictory.

        Me, I've been castigated by merlyn for using ref($caller), and I've (sort of) come around to his view. That is, $obj->new() just always struck me as a perfectly reasonable way to obtain a new, 'blank' object of the object's class. Expecting it to clone just never made any sense to me (if you meant it to clone, you'd've named it clone(), right?). But I've come to sense that I'm in the minority on this one, and calling $obj->new() hasn't ever been truly necessary in my code anyway; if this is going to be that confusing to that many people, then it's a de facto bad idea. (Though still, I'd like to know how many people would really be confused by this, and how many wouldn't be, but are just saying that someone else may get confused.)

        -- Frag.

        I'm reading through perltoot(1), trying to grok perl's way of doing OO, and it actually recommends doing just what Theseus did. From perltoot:

        sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{NAME} = undef; $self->{AGE} = undef; $self->{PEERS} = []; bless ($self, $class); return $self; }

        So is this only recommended if you plan to allow for inheritance? Or did I miss something?

        -Dan

      Maybe I just don't understand WHY the ref($cargocult) idea is so bad. To me, it makes perfect sense... If someone calls the constructor on an instance rather than the class, it forces it to act as if it were called on the class. Isn't this "correct" in most cases?

      new is new and clone is clone. Conviently merging the two into one and differentiating by the call context feels like an icky version of polymorphism.

      btw: Great node, but I gotta tell ya- there are days when I wish I was bagging groceries rather than coding/debugging/supporting. :)

      Here are some nodes w/ some really good explanations:

      Ovid's (Ovid - minor code nits) Re: Adding autoloaded methods to symbol table with using strict refs
      merlyn's ref($proto) - just say no!

      It is bad because while you can have the constructor work fine if someone is confused about the difference between a class and an instance of the class, you cannot perform the same trick for any other non-trivial methods. See Re (tilly) 2: Paradigm Shift - Dual Use Constructors for more detailed discussion of that point.