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?
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 = [];
| [reply] [d/l] [select] |
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...) | [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] [select] |
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. | [reply] |
|
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.
| [reply] [d/l] |
|
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.
| [reply] |
Re: Help!!!! POOP is confusing me!
by pjotrik (Friar) on Jul 16, 2008 at 12:07 UTC
|
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. | [reply] [d/l] |
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
| [reply] |
|
|