Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Help!!!! POOP is confusing me!

by bittis (Sexton)
on Jul 16, 2008 at 11:34 UTC ( [id://697941]=perlquestion: print w/replies, xml ) Need Help??

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

Hey guys, thought i would ask my question here, i am new to perl and moving rather quickly in it, trying to write POOP code which seems to be more of a hustle in Perl than any other non scripting language i ve used so far.

Lets take the following example:

package Farm; use strict; use warnings; sub new { my $className = shift; my $self = { $farmName,"", "farmMamals",(), "farmBirds",() }; bless $self,$className; return $self; } sub addFarmBirds { my self =shift; my tempBirds=[] ; # right way of initialising an array ?? if (@_){ @tempBirds=@_}; #now for the part i dont understand $self->{farmBirds} = @tempBirds; return } }

Here my intention is to declare a hash of variables that belong to the specific object (forgive my poor terminology, still trying to get the gribs of it). From what i understand farmBirds is declared as an array (not a reference to one).
If i now call myFarm->addFarmBirds(@someFarmBirdsArray) will that array's items be placed inside the farmBirds array internal to the object "myFarm"? Or are the variables i declared in the class Farm stored as references?
will something like my @birds = $self->{farmBirds}; successfully make a copy of the farmBirds array in the @birds array? It doesnt not appear to be the case, any ideas on how i can make that happen?

Replies are listed 'Best First'.
Re: Help!!!! POOP is confusing me!
by moritz (Cardinal) on Jul 16, 2008 at 11:53 UTC
    my self =shift; my tempBirds=[] ; # right way of initialising an array ??

    All Perl variables need sigils, so you'd write that as

    my $self = shift; my @tempBirds; # no initialization needed

    Or if you want to work with an array ref instead:

    my $self = shift; my $tempBirds = [];
Re: Help!!!! POOP is confusing me!
by almut (Canon) on Jul 16, 2008 at 13:09 UTC
    are the variables i declared in the class Farm stored as references?

    Yes, or at least, they should be (except if the value is a scalar already)... If an array is nested in another data structure (the hash $self here), it always needs to be via a reference (in Perl).

    will something like my @birds = $self->{farmBirds}; successfully make a copy of the farmBirds array in the @birds array?

    No, to make a copy you'd need to write

    my @birds = @{ $self->{farmBirds} };

    The @{ ... } dereferences the "farmBirds" attribute value, which is presumed to be an arrayref.

    Here's how your code might look like when fixed:

    ___ Farm.pm ___

    package Farm; use strict; use warnings; sub new { my $className = shift; my $self = { farmBirds => [], # initialisation not strictly required, # but good for documentation purposes... # ... }; bless $self, $className; return $self; } sub addFarmBirds { my $self = shift; push @{ $self->{farmBirds} }, @_; } sub getFarmBirds { my $self = shift; return @{ $self->{farmBirds} }; } 1;

    ___ some script that uses the class ___

    #!/usr/bin/perl use strict; use warnings; use Farm; my $farm = Farm->new(); $farm->addFarmBirds( qw(X Y Z) ); my @birds = $farm->getFarmBirds(); print "@birds\n";

    I chose to add an accessor getFarmBirds, which returns the list of farm birds that you can then copy into an array — i.e. the values will be duplicated in this case.  Having accessors is generally recommended, as it helps keep the object-internal data structures encapsulated, the advantage being that if you later need to modify them, you won't need to change every piece of code that's using the class as well... Put differently, the accessor provides a defined API that the user of the class can rely on — the internal representation of the data becomes irrelevant (e.g. you might later want to store the actual values in a database, or some such...).

    (BTW, as Moose has been mentioned, I should point out that this sample is using nothing but the "conventional" Perl 5 object model. This is not meant to say, however, that looking into Moose wouldn't be a good idea...)

      Hey there, thank you all for your answers, i was not sure if variables where stored as references in the class or not, and i was trying to store an array into a scalar value containing the reference, the result was that i was storing the size of the array.
      push @{ $self->{farmBirds} }, @_;
      was what i should have been writting

      Also returning it i ended up returning the reference (which ended up being the size of the array), instead of returning it like   return @{ $self->{farmBirds} };

      As for Moose it seems to be making object creating and handling much easier, but what troubles me is that it does not seem to be following a c++/java style of handling objects which programers coming from such languages might be used to, i ll play around with it though

      Thank you for all your help

        As for Moose it seems to be making object creating and handling much easier, but what troubles me is that it does not seem to be following a c++/java style of handling objects which programers coming from such languages might be used to, i ll play around with it though

        Not following the C++/Java way is a good thing IMO. Moose strives to be more Perl-ish and is derived largely from the Perl 6 spec (along with contributions from other languages such as Ruby, OCaml, Java, etc). Here is what your code looks like in Moose

        package Farm; use Moose; has 'farmName' => ( is => 'rw', isa => 'Str', default => sub { "" }, ); has 'farmBirds' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] }, ); has 'farmMammals' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] }, ); 1;
        When you call Farm->new everything will be initialized for you and so you can start writing code with thart object right away, like so:
        my $farm = Farm->new; $farm->farmName('Old Mac Donald'); push @{$farm->farmBirds} => 'Chicken'; push @{$farm->farmMammals} => 'Pig';
        You can even initialize the attributes on your own from the constructor, like so:
        my $farm = Farm->new( farmName => 'Old Mac Donald', farmBirds => [ 'Chicken', 'Duck' ], farmMammals => [ 'Pig', 'Cow' ], );
        The core goal of Moose is to take the tedium out of Perl 5 OOP (which you actually commented on in your original post) by making Perl OOP less about coding the mechanisms of OOP and more about creating the objects and modeling your problem domain.

        -stvn
Re: Help!!!! POOP is confusing me!
by jds17 (Pilgrim) on Jul 16, 2008 at 11:58 UTC
    Since you are just starting out with Perl and are unspoiled from the old ways of doing OOP in Perl, I would strongly suggest to use the IMHO best way of OO in Perl 5.x, namely Moose and forget about the others for the time being. It is much cleaner and easier to understand and you don't have to handle hashes or other data structures to represent your objects.

    That being said, your code won't run as it stands, there are many compilation errors because of undefined symbols, a non-matched closing bracket and barewords "self" and "tempBirds".

    I cannot understand exactly what your problem is. Can you please get your code into a runnable state. Then I will have a chance to analyze the real issue.

      I'd simply lay off OOP for a while until some mastery of the fundamentals - sigils, references, etc. - is gained. I think once one gets to that point, to move on to perldoc perltoot rather than Moose.

      Moose is great and everything, but one has to eventually be spoiled by the "old ways" if you are ever going to understand most existing code. Beyond that, once you've got a good hold on references I think the old school object implementation has pretty low overhead to learn.

        You are right, of course those basics should come first. I just thought, maybe bittis' main motivation is to evaluate how OOP can be done with Perl, so I threw in the reference to Moose to show him a nice way to do it.
Re: Help!!!! POOP is confusing me!
by pjotrik (Friar) on Jul 16, 2008 at 12:07 UTC

    The initialization of $self is wrong as well. You probably wanted to write:

    my $self = { farmName => '', farmMammals => [], farmBirds => [] }

    Usage of => improves readability and allows you to omit apostrophes on LHS
    $ in $farmName makes no sense - only if you wanted a hash item indexed by the value of variable $farmName
    () is an empty list, inside a list it's the same as if it weren't there at all. [] is an empty arrayref, that's what you need.

Re: Help!!!! POOP is confusing me!
by GrandFather (Saint) on Jul 16, 2008 at 21:31 UTC

    We recommend that you always use strictures (use strict; use warnings; - see The strictures, according to Seuss).

    Oh, hold on a moment. You did use strictures. In that case how come there are at least eight strict violations in the code you posted?

    Aside from that there are a couple of global variables which are generally bad news and, OO issues aside, some fairly basic misunderstandings of Perl syntax.

    Take a stroll through the Tutorials section here. Buy or borrow a copy of the Camel (Programming Perl). Oh, and fixing all the errors highlighted by use strict; before posting code is smart too ;).


    Perl is environmentally friendly - it saves trees

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://697941]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-04-19 05:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found