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

Hi Monks.

I am currently learning how to design object oriented programs in Perl and, being very familiar with Java, I began to wonder how the former differs from the latter in this particular aspect. For example:

public class Example { private String name; private int score; public Example(String myName, int myScore) { name = myName; score = myScore; } public String getName() { return name; } }


In the above Java class, both 'name' and 'score' are instance variables with a scope (visibility) that extends to both the constructor and the getName method even though the getName method was not constructed with a parameter (the parentheses are empty). Is Perl constructed in a similar manner? In other words, can 'instance variables' be defined outside a constructor? If so, are they visible within every subroutine (method)?

#!/usr/bin/perl use strict; use warnings; package Example; # Can variables be defined here? With package level # visibility? sub new { my $class = shift; my $self = { _name => shift, _score => shift, }; bless $self, $class; return $self; } sub getName { my ($self) = @_; return $self->{_name} || 'No name has been defined!'; } sub getScore { my ($self) = @_; return $self->{_score} || 'No score has been entered!'; } 1;


Is passing variables between methods a common practice in Perl? Can you define a class method in Perl?

Thanks for the help monks.

An inquisitive monkette

Replies are listed 'Best First'.
Re: Object oriented Perl and Java: A brief examination of design.
by Athanasius (Archbishop) on Jan 29, 2014 at 04:53 UTC

      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.

        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.

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Moo is pretty light and is fairly suitable for most non-swaths-of-RAM-situations. I've used it plenty for small utility scripts when I need OO. The slight tradeoff in speed is definitely made up for in readability.

        Three thousand years of beautiful tradition, from Moses to Sandy Koufax, you're god damn right I'm living in the fucking past

      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.
        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,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

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
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
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 :-))