Re: Object oriented Perl and Java: A brief examination of design.
by Athanasius (Archbishop) on Jan 29, 2014 at 04:53 UTC
|
# Can variables be defined here? With package level
# visibility?
Yes, but then they will be class variables, not object (instance) variables. Instance variables are defined within the constructor, as in the code shown.
Please note that we are talking here about Perl’s native, core OO facilities. Most OO Perl programmes are today written using Moose, Moo, Mouse, etc. (see Re^3: Class confusion when testing using ref()).
Hope that helps,
| [reply] [d/l] |
|
|
For clarity, instance variables are defined within methods and while in many classes they are all defined in the constructor (method) this is not always so.
Most OO Perl programmes are today written using Moose, Moo, Mouse, etc.
I'm sure that many are - but "most"? Do you have any data to back this up? I've been using Moo on and off for a couple of years and have just returned to it in the last week or so. Building a class using the current docs I find that my version of the module is now out of date but that doing the upgrade requires a whole heap of work because of all the (mostly new) dependencies which also serves to reinforce how heavy it is, despite a contrary statement of its aims.
We don't all write daemons or other persistent code where startup time is not a consideration. We don't all have swathes of memory at our disposal to fill with cascades of module dependencies. We don't all have deployment environments where module upgrades can be made with impunity. At least, not all the time :)
The "modern" OO module frameworks such as these are a boon for sure, but they are not a panacea. And while they are probably the simplest, easiest introduction to Perl OO for java programmers like the anonymous OP, if they hide what's going on under the bonnet (or the programmer never thinks to look) the lack of appreciation of the OO core will always hold the programmer back.
Those of us who can remember the introduction of OO into Perl will have been writing such bare-bones code for a decade or more. Many of us still do. While the resulting source may have a little too much boilerplate for some tastes, it will be fast, light and portable.
In summary, it's horses for courses. Learn both approaches, take the best from each and choose from that experience which to apply in relevant situations.
I'll get off my soapbox now. Thank you for listening.
| [reply] |
|
|
For clarity, instance variables are defined within methods and while in many classes they are all defined in the constructor (method) this is not always so.
I guess I should have said: Mostly, instance variables are defined within a constructor, or within a method called (directly or indirectly) by a constructor. But in some (rare?) cases, instance variables are recycled (via constructors and destructors) from an object pool created in a BEGIN block and stored in a class variable (array or hash) at package scope. (Am I still missing something here?)
I'm sure that many are - but "most"? Do you have any data to back this up?
No, that was merely my impression from reading PerlMonks! But the point I wanted to get across to the OP was this: If you come to Perl from an OO language like Java or C++, Perl’s core OO features may appear underwhelming. But Moose and related modules are in common use, and provide many of the OO features you were expecting. So by all means learn how OO works in Perl, but don’t judge “Perl OO” by its core mechanisms alone.
I'll get off my soapbox now.
The issues you raise are worth discussing, and your points are well made.
| [reply] [d/l] |
|
|
| [reply] |
|
|
Hi Athanasius.
Thanks for the quick and helpful reply. Could you provide a simple example of how one would use a class variable in Perl? Is there any other way, using the code I wrote, to access the value of an instance variable with a method that did not receive the variable as a parameter? Simply for clarification, a class variable could be defined outside the constructor but still as a lexically scoped, 'my' variable? What about using 'our'?
For the curious, this is not homework :)
Thanks.
| [reply] |
|
|
Could you provide a simple example of how one would use a class variable in Perl?
Sure!
#! perl
use strict;
use warnings;
package Widget
{
my $count = 0;
sub new
{
my ($class, @args) = @_;
my %self = @args;
++$count;
return bless \%self, $class;
}
sub DESTROY { --$count; }
sub get_count { return $count; }
}
package main;
my $w1 = Widget->new(name => 'foo', value => 42);
my $w2 = Widget->new(name => 'bar', value => 7);
my $w3 = Widget->new(name => 'baz', value => 12);
printf "Now there are %d Widgets\n", Widget::get_count;
undef $w1;
printf "Now there are %d Widgets\n", Widget::get_count;
Output:
15:52 >perl 856_SoPW.pl
Now there are 3 Widgets
Now there are 2 Widgets
15:52 >
Is there any other way, using the code I wrote, to access the value of an instance variable with a method that did not receive the variable as a parameter?
Not that I can think of. Anyway, that’s not how it’s supposed to work in Perl.
a class variable could be defined outside the constructor but still as a lexically scoped, 'my' variable? What about using 'our'?
Using our creates a package variable, which can then be exported to other packages, or accessed directly by other packages using the $Widget::count syntax. Using my creates a lexical variable, which is scoped to the package. The rule is: use a lexical (my) variable unless you have a good reason to make it a package/global (our) variable. Update (Jan 30, 2014): See Ovid’s classic post 'our' is not 'my'.
Hope that helps,
| [reply] [d/l] [select] |
|
|
our %error_dictionary = ...;
our %cached_templates = ...;
sub get_template { .... check cache or store in cache ... }
sub get_error { $error_dictionary{...} ... }
If these were, my lexical, then its hard to peek inside for folks that need to ...
Being our globals, anyone who wants to peek can do so at their own risk, an know to stick with the official api for officialness
one or the other, it doesn't really matter, this is the least important type of implementation detail... but you can't go wrong with openness (our our our)
https://metacpan.org/module/DROLSKY/perl-5.15.6/pod/perlootut.pod, chromatics free book Modern Perl, Moo, Re^3: High level OOP query (internal data) | [reply] [d/l] |
Re: Object oriented Perl and Java: A brief examination of design.
by Laurent_R (Canon) on Jan 29, 2014 at 08:12 UTC
|
As a side note, even when you are not doing OO, you can extend the scope of variables to several functions if you need to. For example, two subs can "close" over the same variable by defining them in a lexical block:
{
my $val;
sub set_value {
$val = shift;
}
sub get_val {
return $val;
}
}
Now, $val's scope extends to the two functions. Or you can make a function that manufactures an anonymous closure:
sub create_func {
my $val = shift;
return {
$val ++;
return $val;
}
}
my $increment_coderef = create_fund(1);
my $value = $increment_coderef->(); #returns 2
my $value = $increment_coderef->(); #returns 3
| [reply] [d/l] [select] |
Re: Object oriented Perl and Java: A brief examination of design.
by tobyink (Canon) on Jan 29, 2014 at 09:39 UTC
|
"In other words, can 'instance variables' be defined outside a constructor?"
They can using mop, a module which is planned for inclusion in a future version of Perl (perhaps 5.22 or 5.24), though there's a trial version on CPAN already.
The syntax differs from normal Perl variables, in that instance variables are declared with has instead of my, and instead of having a $ sigil (like $foo) they have a $! twigil (like $!foo).
For example:
use v5.16;
use mop;
use warnings;
class Example {
has $!name;
has $!score;
method getName () {
return $!name;
}
method getScore () {
return $!score;
}
}
my $eg = Example->new(name => "Bob", score => 9.9);
say $eg->getName;
say $eg->getScore;
The mop module is inspired by the already-existing, and more stable Moose framework. Here's how you'd accomplish the same thing in Moose:
use v5.14;
use warnings;
package Example {
use Moose;
has name => (is => 'ro', reader => 'getName');
has score => (is => 'ro', reader => 'getScore');
}
my $eg = Example->new(name => "Bob", score => 9.9);
say $eg->getName;
say $eg->getScore;
Or you could use Moo:
use v5.14;
use warnings;
package Example {
use Moo;
has name => (is => 'ro', reader => 'getName');
has score => (is => 'ro', reader => 'getScore');
}
my $eg = Example->new(name => "Bob", score => 9.9);
say $eg->getName;
say $eg->getScore;
Or Moops:
use Moops;
class Example :ro {
has name => (reader => 'getName');
has score => (reader => 'getScore');
}
my $eg = Example->new(name => "Bob", score => 9.9);
say $eg->getName;
say $eg->getScore;
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
| [reply] [d/l] [select] |
Re: Object oriented Perl and Java: A brief examination of design.
by Bloodnok (Vicar) on Jan 29, 2014 at 13:26 UTC
|
Instance/object variables can be defined outside a constructor if something approaching the flyweight pattern is adopted...
package MyPkg;
my @Instances; # Visibility restricted to package by lexical declarati
+on
sub new {
my $self = shift;
my $opts = ref $_[0] ? shift : { @_ };
push @Instances, { %$opts };
return bless \(my $me = $#Instances), $self;
}
sub getScore {
my $self = shift;
return $Instances[$$self]->{score};
}
As for class methods, all subs declared in a package are, by definition, class methods since the package is the equivalent of a class. The invocation context is determined in the subs/methods themselves e.g.
package SomeClass;
sub classMethod {
my $self = shift;
die("Not an object/instance method") if ref $self;
.
.
}
sub objMethod {
my $self = shift;
die("Not an class method") unless ref $self;
.
.
}
Once again, just my 10 penn'orth FWIW, hope it's of interest/use to you
A user level that continues to overstate my experience :-))
| [reply] [d/l] [select] |