http://qs1969.pair.com?node_id=296978

I saw a thread recently about inside-out objects, and started thinking about the different ways to do OOP in Perl. At the moment, I generally just bless a hash and access its members (e.g. $self->{member}). As Abigail-II pointed out, though, this can make misspellings into tricky runtime errors. Also, the syntax seems kind of ugly to me.

So I was wondering what OO methodology the Perl Monks use. Some of the ones I'm familiar with are:

What kind of OO programming do you use and why?

I always thought it would be more realistic if the Matrix were attaching the humans to long poles and using them to beat their cake batter. Then Morpheus could say "to turn a human being into THIS" and hold up a big birthday cake. - slashdot

Edit by tye, ephasize "you" in title, close B and I tags

Replies are listed 'Best First'.
Re: How do YOU do OO in Perl? (constant offsets)
by tye (Sage) on Oct 06, 2003 at 16:50 UTC

    I'm partial to const subs and namespace purity:

    package My::Class; use vars qw( $VERSION ); BEGIN { $VERSION= 1.01 } package My::Class::_implement; BEGIN { my $offset= 0; for my $member ( qw( FOO BAR BAZ BIF ) ) { eval "sub $member() { $offset }; 1" or die "eval failed: $@"; $offset++; } } sub My::Class::GetObjectPackage { my $class= shift(@_); return $class . "::Object"; } sub My::Class::new { my $class= shift(@_); bless [], $class->GetObjectPackage(); } sub My::Class::Object::Foo { my $self= shift(@_); my $value= $self->[FOO]; $self->[FOO]= shift(@_) if @_; return $value; }

                    - tye
Re: How do YOU do OO in Perl?
by demerphq (Chancellor) on Oct 06, 2003 at 16:50 UTC

    I use a mixture of blessed references (I use blessed scalars, regexes, code, arrays, hashes, in fact the only thing I havent used as a class type sofar is blessed globrefs) and inside out objects.

    Recently I've found myself doing more things with inside out objects or properties. Like when im adding some property to a class that I dont want dumped by Data::Dumper Ill often implement it inside out style. Also if you need to add extra data to a previously implemented blessed code ref or scalar ref, then they come in real handy.)

    I almost never use automatic tools to construct my classes. (Dont trust wizards you didnt write.) Primarily because they tend to force you to use OO models that are alien to Perl, and usually are not as flexible as I want them to be. Im more likely to write a sub generator for loop than I am to hand it over to an external module.


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


Re: How do YOU do OO in Perl?
by dragonchild (Archbishop) on Oct 06, 2003 at 16:24 UTC
    I have my own baseclass that I wrote and use myself. It creates array-based objects, generates methods, and exports a function called attrs(). So, a class will look something like:
    package Foo; use BaseClass; our @ISA = qw(BaseClass); attrs qw( foo bar baz ); sub init { my $self = shift; my %options = @_; # Do some stuff here return $self->SUPER::init(%options); } sub foo { my $self = shift; # Do some validation here return $self->_foo(@_); }

    It handles diamond inheritance, on-the-fly methods, and provides a simple (but not obtrusive) separation of interface and implementation. Also, you can't mispell a method name and have it DTWT silently, as with direct access to hashes can.

    I've never uploaded it to CPAN because there are a plethora of class classes out there. I also never really cared to learn Class::Struct, Class::MethodMaker, and the like, because this does what I need it to do, and nothing more. *shrugs* I probably should, at some point, if only to get into the mainstream.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: How do you do OO in Perl?
by herveus (Prior) on Oct 06, 2003 at 16:22 UTC
    Howdy!

    One way to sort methods is "hand-rolled" versus "automated". Class::Struct (IIRC) is an example of automated, but you can't subclass (or was that "use it in a subclass"?); it has restrictions on extensibility that might preclude its use. Class::MakeMethods and Class::MethodMaker each offer extensive choices in what you make and how the innards of your class work. I've used one of them (I forget right now which one it was).

    I've hand-rolled hash-based classes as well as ones based on other storage methods -- sort-of inside-out. I don't think I've gone so far as to meaningfully reinvent the wheel in automated generation.

    Recently, I got a week of Java training at work. I behaved myself. Java presented some interesting ideas along with the (IMO) excessive bondage and discipline. I see Java having influence on my Perl programming (in a good way). Of course, (not intending to do the language flame thing) some of the contortions one must go through in Java are related to the fact that everything is an object...well, almost...unless it is a primitive data type... On the other hand, it has broadened my horizons on setting things up, and led me to consider how to steal from Class::*mumble* to make a Class::Java::Autogenerate or something that will create class files with the scut-work done automagically to write the accessor/mutators and declare the attributes and whatever else comes to mind to autogenerate.

    yours,
    Michael
Re: How do YOU do OO in Perl?
by bakunin (Scribe) on Oct 06, 2003 at 21:32 UTC
    The node I have started for Class::Struct is worth a look:

    For those of you who doesn't want to read it, let me copy my remark:

    Class::MethodMaker and Class::MakeMethods are indeed excellent modules. I'm congratulating the authors, and especially, simonm and friends for the excellent documentation provided for the module.
    But let's set one thing straight. MethodMaker seems more compact than MakeMethods.
    I'll definitely try both. OOP is my addiction anyway... I also want to give credit to Mr Damian Conway.
    In my opinion, he has written one of the best programming books in (programming) history.
    And I am very lucky that, the book is the "Object Oriented Perl." He provides a whole chapter on Class::Struct and Class::MethodMaker.
    I think MakeMethods is written after the book is published!!


    Now, the interesting thing about OO Perl is that you can bless anything you can reference...hashes,arrays, Regexps, other objects, and my favorite, coderefs... Here are some links I've been compiling nowadays (mostly coderefs though):

    1) Again and again: Object Oriented Perl (e-book and sample chapters available in pdf format)
    2) AnonymousSubroutineObjects
    3) Limbic~Region's MultiMethod Closures
    4) merlyn's column on subrefs(no OOP)

    5) ProxyObjects
    6) broquaint's "Closure on Closures"

    7) Very, very interesting: Class::Prototyped
    8) Class::Translucent


    The links also contain many other links.

    These came to my mind now.
    Any additions anyone?? For example on blessing regexps and objects? Possible cool uses?? Let's grow the list.
Re: How do YOU do OO in Perl?
by hardburn (Abbot) on Oct 06, 2003 at 17:49 UTC

    . . . (e.g. $self->{member}). As Abigail-II pointed out, though, this can make misspellings into tricky runtime errors.

    Just thought of this: Create scalars with package-wide scope to hold the key names of your attributes. For instance:

    package Foo; use strict; my $attr_bar = 'bar'; my $attr_baz = 'baz'; sub new { # Constructor as normal } sub bar { my $self = shift; $self->{$attr_bar} = shift if @_; $self->{$attr_bar}; } 1;

    This makes your data available to subclasses and will create errors under use strict if you misspell the variable used to access the hashref. It's probably best if you make the variable names and key names different, in case you forget to add the $ sigal.

    I don't know a way around the "uglyness", except to wait for Perl6, which should have a much nicer object system.

    Anyway, on to your actual question.

    Most of my objects are blessed hashrefs. Occasionally, I'll use a closure or simple class methods. Since Perl has so many ways of doing objects, and the term 'Object Oriented' is rather broadly defined, I suspect I've used a bunch of different object systems without even noticing it.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: How do YOU do OO in Perl?
by perrin (Chancellor) on Oct 06, 2003 at 18:36 UTC
    Lately I've been using Class::DBI, which uses Class::Accessor to make the accessor methods. This has been working well. When I make non-Class::DBI objects I just use simple blessed hashes.
Re: How do YOU do OO in Perl?
by tilly (Archbishop) on Oct 07, 2003 at 06:11 UTC
Re: How do YOU do OO in Perl?
by danb (Friar) on Oct 06, 2003 at 19:07 UTC

    I prefer to use Class::MethodMaker. In one instance, I extended it for my needs (to modify a data_accessor method so that it also calls the parent class).

    -Dan

Re: How do YOU do OO in Perl?
by vadim_t (Acolyte) on Oct 07, 2003 at 13:17 UTC
    I use normal hash blessing with a small improvement for avoiding bugs due to inheritance. Here's an example:
    package Foo::Bar; my $pkg = __PACKAGE__; sub new { my ($class) = @_; my $self = {}; bless($self, $class); $self->{$pkg} = {}; return $self; } sub setvar { my $self = shift; my $priv = $self->{$pkg}; $priv->{variable} = 1; }

    Each method has two variables, $self, which is the blessed hash and is used to call methods, and $priv, which is used to keep the private variables. So, if you use this class, 'variable' will be $self->{Foo::Bar}->{variable}. If a class using the same technique, say, Foo::Bar::Improved also defines the same variable, and inherits from Foo::Bar, then the variable be $self->{Foo::Bar::Improved}->{variable}. No conflict.

    You won't see that in the module I posted here though, because it was written a long time ago when I didn't do this yet.

      s'$self->{$pkg} = {};'$self->{ + __PACKAGE__ } = {};';
      update: but it's not prettier ;)(1 teenie-weenie + versus another variable? come on)

      MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
      I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
      ** The third rule of perl club is a statement of fact: pod is sexy.

        $pkg is the same as __PACKAGE__, look above. I just use $pkg to make it shorter and prettier.
        I'd prefer $self->{(__PACKAGE__)}. One more character, but it doesn't look so noisy.

        Makeshifts last the longest.

Re: How do YOU do OO in Perl?
by tsee (Curate) on Oct 08, 2003 at 13:51 UTC

    Most of the time, I write straightforward Perl OO code using blessed hashrefs and cloning of objects when new() is called on prototypes. Add some AUTOLOAD from a fixed set of attributes (and run-time method generation for speedup).

    I try to keep everything nice and subclassable, but when that just wouldn't work, I offer some extension mechanism via delegation like Math::Symbolic::Custom. Also, I tend to offer two interfaces. One kept as simple as possible for the general usage case and one involving things like closures for the ultimate control in pathological cases.

    Steffen

Re: How do YOU do OO in Perl?
by Juerd (Abbot) on Oct 10, 2003 at 06:54 UTC

    My OO style is simple and clean, thanks to Attribute::Property:

    package Some::Class; sub new : New { my ($self) = @_; exists $self->{$_} or croak "Mandatory argument '$_' missing" for qw(id foo); return $self; } sub id : Property { /^\d+\z/ } sub foo : Property; sub bar : Property; sub blah : Property { $_ < 50 } sub _private : method { my ($self) = @_; ... } sub do_something : method { my ($self, $quux) = @_; ... }
    And this is how you use this Some::Class:
    my $thing = Some::Class->new( id => 15, foo => "Hello" ); $thing->foo =~ s/e/a/; $thing->id++; $thing->do_something($$); $thing->blah = 10; $thing->blah = 60; # dies
    See also $foo->bar = 14; and $foo->bar = 14; revisited: Attribute::Property.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      That's very clean, indeed. I think I'll try combining it with Acme::Dot. Thanks for the info.

      Bill
Re: How do YOU do OO in Perl?
by Anonymous Monk on Oct 08, 2003 at 12:06 UTC
    I exclusivly use Class::Maker, because i wrote it. I exclusivly write robust, deluxe, fancy, feature-rich, badly-documented stuff ;) Newly i use it in combination with Data::Type:
    class 'Idiot', { public => { string => [ qw( name title ) ], int => [ qw( score ) ], }, types => { string => STD::VARCHAR(80), int => STD::INTEGER, } }; sub Idiot::talk : method { my $this = shift; use IO::Extended qw(:all); printfln "I am %s and stupid", $this->name; } my $murat = new Idiot name => 'murat', title => 'Mr.', score => 10; $murat->talk;
    Cheers, Murat
Re: How do YOU do OO in Perl?
by Nomad (Pilgrim) on Oct 10, 2003 at 12:57 UTC

    At the moment, I generally just bless a hash and access its members (e.g. $self->{member}). As Abigail-II pointed out, though, this can make misspellings into tricky runtime errors. Also, the syntax seems kind of ugly to me.

    Perhaps I'm being a bit dull here, but you could just use what is often called 'good manners', but is sometimes referred to as true OO. That is knock at the front door rather than sneak in through the cellar and use proper getter and setter methods to access your attributes and you can even do this without using things like Class::MethodMaker.

    Of course, writing a load of getters and setters can get boring. Using AUTOLOAD without safeguards might cause all sorts of autovivification which is dangerous (I should know, I do it all the time).

    Therefore the best way, IMHO, is the way that TheDamian suggests in Chapter 3 of his book, Object Oriented Perl, pp 91ff. This is to set up a hash to look after accessibility, like this:

    { my %_attr = { _attr1 => 'read', _attr2 => 'write', } sub _accessible { my ($self, $attr, $mode) = @_; $_attr{$attr} =~ /$mode/; } }

    Then lower down you can have your AUTOLOAD:

    sub AUTOLOAD { my ($self, $value) = @_; ## was it a get method? $AUTOLOAD =~ /.*::get(_\w+)/ and $self->_accessible($1, 'read') and re +turn $self->{$1}; ## was it a set method? $AUOTLOAD =~ /.*::get(_\w+)/ and $self->_accessible($1, 'write') and d +o { $self->{$1} = $value; return} die "No such method: $AUTOLOAD, $!"; }

    Now, your program will die if you try to access an attribute that doesn't exist. Perhaps it would be better if it threw an exception if you try to set an attribute that is read-only, but in that version it doesn't.

    Enjoy!

Re: How do YOU do OO in Perl?
by Anonymous Monk on Oct 08, 2003 at 12:03 UTC
    <xmp>
    I exclusivly use Class::Maker, because i wrote it. I exclusivly write robust, deluxe, fancy, feature-rich, badly-documented stuff ;)

    Newly i use it in combination with Data::Type:

    class 'Idiot', { public => { string => [ qw( name title ) ], int => [ qw( score ) ], }, types => { string => STD::VARCHAR(80), int => STD::INTEGER, } }; my $murat = new Idiot name => 'murat', title => 'Mr.', score => 10; # + out of 10
    </xmp>

    Murat

    Edit by tye, preserve formatting