http://www.perlmonks.org?node_id=618766

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

We write a lot of Perl code where I work, and we write a lot of OO Perl in the sense that we use bless and call methods on objects and classes a lot. But I'm starting to realize that we are Perl developers writing OO Perl in much the same way as a C programmer writes Perl, if that makes sense. Part of the problem is that almost everyone here comes from a background of functional programming, so there is really no culture of OO principles.

This is to say that I know that it's not an all or nothing decision to use OO techniques, but I feel like, where we are using it, we're not taking full advantage of its capacities. I came to this conclusion while reading through Fowlers Refactoring and as I'm reading through the "Bad Smells in Code" chapter I'm seeing a lot of things that we're doing. This seems to be a good start for looking for ways to improve our abilities with OO principles.

I'd love to hear recommendations on what other resources people have found useful for learning how to better apply OO techniques in Perl. Again, I'm well versed in the technical implementation of objects in Perl and there is certainly a wealth of information on the topic, it's really more the technique that I'd like to improve.

perl -e 'split//,q{john hurl, pest caretaker}and(map{print @_[$_]}(joi +n(q{},map{sprintf(qq{%010u},$_)}(2**2*307*4993,5*101*641*5261,7*59*79 +*36997,13*17*71*45131,3**2*67*89*167*181))=~/\d{2}/g));'

Replies are listed 'Best First'.
Re: Really Writing Object Oriented Perl
by stvn (Monsignor) on Jun 01, 2007 at 17:56 UTC
    We write a lot of Perl code where I work, and we write a lot of OO Perl in the sense that we use bless and call methods on objects and classes a lot. But I'm starting to realize that we are Perl developers writing OO Perl in much the same way as a C programmer writes Perl, if that makes sense.
    <rant>

    Unfortunately, this makes all too much sense. Perl's OO system is really just a thin veneer over the module system and reference types, which really are just the primative building blocks for a real object system. This is not really all that uncommon though, many languages made the move from structured programming (modules, abstract data types, etc) to OO by similarly enhancing existing features. But as the 90s moved into the 00s and Java became every managers dream come true (and many a developers nightmare) the idea of "True" and "Pure" OO became more important than an OO tacked-on to an existing feature set. To be honest, Perl 5 is behind the times on this, Languages like Python and Ruby, which have much more complete OO systems are really making Perl 5 look bad (at least IMHO). Sure, we have TIMTWODI so we can do our OO any way we want, but in practice this has lead to lots of incompatible approachs and extreme work arounds like Inside-Out classes. If you dont believe me you need only see all the crap people are talking about Perl on the Bugzilla wiki. So much of the "Cons" being brought up are not really cons, but bad usage patterns and misunderstandings of features. And while I really hate to say it, it is my opinion that this is really a case of "TIMTWODI gone bad". A lack of any kind of OO "Best Practices" (and no I do not mean TheDamian's book) is hurting Perl. But anyway enough ranting ...

    </rant>
    I'd love to hear recommendations on what other resources people have found useful for learning how to better apply OO techniques in Perl.

    Practice, practice, practice. There are many good OO books out there which teach OO technique (many already mentioned by other posters), but they are no substitute for actually writing real-world code, and even more importantly, maintaining and extending that same code. The cycle of writing and refactoring of an OO codebase over several years has taught me more than any book ever could.

    -stvn
      I agree. IMHO there's one thing that would help this whole situation: there should be a default, modern, easy to use OO framework/library that's recommended for serious work by the majority of "the perl/OO community" (if there is one).

      Something that:

      • Can subclass any other class that's using bless() the right way with any reference type. (I.e. it should use the inside-out fields technique)
      • works with threads (and fork() emulation on windows) - won't use reference addresses to index fields.
      • works with threads::shared - allows you to share objects across threads with minimal fuss.
      • works with XS extensions and allows for easy mixed perl/XS classes/hierarchies.
      The only thing I can think of is Object::InsideOut, though it could use a simple tutorial, some XS helper functions and possibly a less cluttered interface. Other suggestions are welcome.

      If the community can decide on some default library like that, it should be put in the core.

      I know the tendency is to keep as much as possible out of the core, but a default good OO layer (i.e. not Class::Struct) is just plain needed to be able to write good OO perl. It really is too much work to write reliable OO perl without using external modules.

        There's a small but (I hope) steadily growing ressource about OO on PerlMonks: Anno's meditations, replies and questions.

        While his intentions might be different, I perceive his as an effort to implement OO requirements as close as possible to or into the perl core, with what means perl itself already provides. Following this road one day we might not only have the basics needed to implement an OO system in perl - functions as methods, packages as classes, references, bless, ref and so on - but a robust OO system at the core level, not just tacked-on OO implementations in disparate arbitrary and sometimes redundant or contradictory modules on CPAN.

        OO is "magic" - and the perl sense of "magic" fits; I am looking forward to OO related "Magic Virtual Tables" (see perlguts for those) and handling code, either in the perl core, or in some XS extension provided along with the core.

        Anno's inside-out iplementation via magicext seems to meet all the requirements you have outlined so far.

        A lot of fuzziness will have to be discussed and cleaned up to meet that goal - first thing that comes to mind is the ambiguous use of package, module and class - they are often used as synonyms, but address very different aspects needed for a robust OO implementation; then method lookup...

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      I don't think it's a matter of "making Perl look bad", it depends what you're looking for.

      If you're looking for "everything is an object and all actions are methods" language then Ruby or Smalltalk are your best choices. And *very* fine languages both of them are Perl doesn't match that, neither does Java, Python or C++.

      If you're looking for a good-performing byte-compiled language with no manual compile step, Perl and Python fit the bill, Java and Ruby do not.

      If you're looking for a language where you can read and modify many aspects of the runtime engine, then Perl, Python, Ruby and Objective-C will suit you, Java and C++ won't.

      If you're looking for a language that lets you use aspects of functional, OO and Quantum computing, and you want full closures and continuations, you're going to have to bleed at the edge with Perl 6.

      That last one was a bit tongue in cheek, but I think you can see where I'm going. Of course if you want to use certain products then your choice is made for you - and it's simply a matter of whether you can stomach the language. Want a pre-built continuations based web framework? You need Seaside and that means Smalltalk. Want an open source eLearning web system with every function you could think of and an active developer community? You probably want .LRN (AOLServer/tcl/plpgsql) or Moodle (php).

      I really hope that language wars can become a thing of the past, that good languages can prosper on their merits, and bad languages can be contained to legacy systems that were started by developers who didn't know any better...

      If you dont believe me you need only see all the crap people are talking about Perl on the Bugzilla wiki. So much of the "Cons" being brought up are not really cons, but bad usage patterns and misunderstandings of features.

      That "crap" stems from avatraxiom's journal, and hidden in the comments there's one that sets some bits straight - but the wiki wasn't updated accordingly...

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Really Writing Object Oriented Perl
by Joost (Canon) on Jun 01, 2007 at 15:17 UTC
      Conway's Object Oriented Perl gives a good overview of available OO techniques in perl and how to use them effectively.
      But Conway's book predates Inside-Out Objects, so it doesn't even mention them.

        Conway's book predates the Perl community's commonplace adoption of the term "Inside-Out Objects". The concept is there; Conway calls them "Flyweight Objects". The terms aren't exact synonyms, but close enough for the present purpose; there's some relevant discussion in this thread.

Re: Really Writing Object Oriented Perl
by moritz (Cardinal) on Jun 01, 2007 at 15:13 UTC
    The problem is thinking in OO.

    Currently I have the problem the other way round, I can think in OO, but I'm having difficulties lerning haskell...

    I'd recommend to read a good book on OO, not necessary a Perl book - I liked "Object Oriented Software Construction" by Bertrand Meyer.

    Once you start thinking in OO-Terms, you'll ask yourself how to do that in perl, and eventually you'll end up using Moose or something ;-)

      I actually find OO in Perl much easier. I don't do a whole lot of OO programming, but when it is useful I would not have it any other way - mainly because I am not restricted in virtually any way.

      As it has been said, Perl OO programming (as does any) requires a lot of practice and refining. Regarding books, Conway's book on OO Perl is not only the best book I've seen on the subject, but the coverage of Perl topics (closures, globs, etc) is by far the best I've seen in any book. It is worth getting even if you have no intention to ever writing OO Perl.
Re: Really Writing Object Oriented Perl
by perrin (Chancellor) on Jun 01, 2007 at 17:36 UTC

    It sounds like the problem is not so much how to use OO in Perl but more how to use OO in a general sense. Most of the Perl OO books and reference materials (with the exception of the perlboot manpage) assume you already know all about OO design, and thus are not very helpful to beginners.

    To learn the theory of effective OO programming, you will have to read non-Perl books. A lot of introductory texts are written using Java for examples these days, and some try to be language-independent. I suggest you head to your local tech book store and browse the introductory OO books until you find one with a tone that you like.

Re: Really Writing Object Oriented Perl
by educated_foo (Vicar) on Jun 01, 2007 at 18:51 UTC
    Wanting to "use more qw(Objects)" is all fine and good, but I don't think writing Perl like a Java (or Smalltalk) programmer will necessarily help you. To use some paradigm in Perl, you need to learn what it lets you do, how to implement it and, at least as importantly, when *not* to use it. I would focus on expressing solutions naturally rather than on forcing them all into a particular box. If you want to learn what OO is good for, play around in Smalltalk, which forces you to use it for everything.
      I agree on all counts.

      Firstly, go get yourself some real OO fun with Smalltalk. You can get a traditional smalltalk environment for free (Squeak) and a lot of excellent Smalltalk texts are online, also for free (free smalltalk books). Doing smalltalk has really helped me "think in OO" much more than I used to.

      Having said that, don't then write OO Perl the way you would write OO Smalltalk. There are two key reasons why I say that.

      Firstly, Perl offers many useful constructs beyond OO that it would be silly to ignore. For instance, don't use a collection class when an array will do. For another example, when you have a problem that lends itself to functional programming, using Perl's functional style will be more succinct, powerful and faster than OO.

      Secondly, and this is a genuine reason, is that of all the things perl does really quickly, method calls is not one of them. Sub calls are slow, method calls are *really* slow. What this means is that when you have two roughly equivalent design choices, one which would result in 1,000 method calls and another that would result in 50 - in perl I would always choose the latter.

      A general way of thinking that I have come up with is to use strict OO concepts at class boundaries, ie. APIs, but within the class only using OO where it makes sense. This allows you, IMO, nearly all of the classic OO benefits, while retaining Perl's expressiveness and performance.

      If you want to learn a great way to design OO class boundaries and APIs, I suggest Domain Driven Design by Eric Evans - it's one of the best software related books I have ever read.

        Excellent advice++ Every word.

        Use OO when OO makes sense, but don't try and force fit everything into the OO-model. OO is a means to an end--and just one of several--not an end in itself.

        Don't ignore the built-in facilities. They're simpler, faster and usually better thought through than most people can write themselves at their first, second or third attempt. Use them and get on with the job, rather than stressing that it's "not OO".

        Don't fuss that the 'bad man' might be able to access your private attributes and methods. Half the time you'll be the potential 'bad man', and if you choose to break encapsulation, you'll do it for good, expendient or deadline driven reasons. The other half of the time, the 'bad man' will be a collegue who's hit a wall that your interface specification didn't consider and he'll consult you for the workaround, And thank your lucky stars that you can when you need to. Go with the flow and improve the interface when time and budget allow. Working, coupled code today is worth 10 times, perfectly decoupled code a month or two from now. If only because it allows you time to discover it's functional shortcomings, early enough to correct them.

        Don't try to predict the future--you'll always get it wrong. Write what you need today, and re-write what you have to, tomorrow. In this imperfect world, the re-write will happen anyway, but in most cases the code you re-write will be a big improvement over anything you could have written today. You'll know more about the problem and more about the solution.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Really Writing Object Oriented Perl
by blazar (Canon) on Jun 01, 2007 at 15:50 UTC
    This is to say that I know that it's not an all or nothing decision to use OO techniques, but I feel like, where we are using it, we're not taking full advantage of its capacities. I came to this conclusion while reading through Fowlers Refactoring and as I'm reading through the "Bad Smells in Code" chapter I'm seeing a lot of things that we're doing.

    As we've discussed both here and elsewhere quite frequently and also very recently, it's officially OK in Perl to speak only a subset of the language, and OO makes no difference. Of course just as in all those other respects, this is not an excuse for not improving one's knowledge of the language if wanting to use it regularly. Code smell is a whole another story, and you should actively work to remove it: learning what's wrong with some code constructs and see what people do instead, may be a good starting point for your improved learning of the OO dialect of Perl.

Re: Really Writing Object Oriented Perl
by doom (Deacon) on Jun 01, 2007 at 22:27 UTC
    Can you tell us what kind of "code smells" you've observed, and also, can you tell us if you've seen any evidence they're really causing you problems? Compliance with doctrine isn't the ultimate goal, of course...

    The one abuse-of-objects practice that I've seen really cause problems is "the Blob anti-pattern": one of the few things I really like about "Objects" is they way they handle encapsulation, and if you've got everything shoveled into one namespace, it hardly matters if you call that namespace an "object" or a "bloated script".

    In general, I've been coming to the conclusion that having a nice barrage of automated tests is the key thing: compared to that, every other issue (choice of language; design patterns; OOP/proceedural; inside-out, upside-down or sideways, etc) is nearly insignificant.

    (Though I don't think "Test First" programming isn't strictly necessary, "Test Soon" is good enough.)

      I think the most troubling thing I see is actually the use of the "Blob anti-pattern" as you mention. We use classes, but only a few, and many of them are enormous. I'm struggling to figure out how to refactor these large classes, which is why I'm reading Fowler's book. But I also want to figure out how to write better OO code so I can avoid spending as much time in the refactoring process.

      In the end, I suppose the best way is to just do it. And reading general OO books is my main plan, I was mostly wondering if there were any resources on Perl OO programming that focused on OO technique as much as or more than the technical aspects.

      perl -e 'split//,q{john hurl, pest caretaker}and(map{print @_[$_]}(joi +n(q{},map{sprintf(qq{%010u},$_)}(2**2*307*4993,5*101*641*5261,7*59*79 +*36997,13*17*71*45131,3**2*67*89*167*181))=~/\d{2}/g));'
        I'm struggling to figure out how to refactor these large classes,

        Okay, well you probably know this already, but a suite of automated tests really does help any sort of refactoring effort (OOP or not). You can split out functionality from one of the large blobs into smaller units, and then re-run the tests on the system to instantly get a pretty good idea if you've broken something.

        Most grand doctrines on software development ultimately strike me as at least 50% snake oil [1] by weight, but test-oriented programming is one of the few that I'm completely sold on.

        Caveat: when you've got lots of tests that check low-level routines, the tests become a kind of institutional weight on changing the way your primitives work. Any change in interfaces breaks your tests as well the code that uses what you've changed, so that's one more thing that needs attention. I don't see any thing to do about this but live with the pain: you really do need low-level tests, and perfectly designed interfaces that never need revision are a fantasy.

        As for general advice on working with Objects: Favor "aggregation" over inheritence if you can -- inheritence is always tempting as a way to share common- code, but it causes problems when you get too fancy with it. Avoid inheritence chains deeper than one or two levels (possibly: reserve inheritence for fixing design errors, avoid using it in initial designs).

        The notion that Objects are a "metaphor" doesn't really work: if you start off with a rule of thumb like "identify the nouns", you're likely to end up with something that's over-designed and that under-performs. My opinion (at the moment at least) is that it's best to just think about classes as bundles of routines that need access to the same data -- and it's perfectly okay to invent new abstractions that have no analog to some physical object (typically you need to come-up with bogo-nouns to convince people these are really "objects": "This is the Wangifier Handler Manager class").

        I strongly suggest looking into the "Hash::Util" module (standard with perl 5.8.0), that provides "lock_keys" and "unlock_keys". You can use these with a hash-ref based object to lock down the existing field names, and help catch typos.

        Try grepping your codebase for things like "$self->{". That will help find places where someone cheated and peeked at the object href directly. Replace those with actual accessors.

        Off the top of my head, that's all I can think of... oh, maybe one more piece of advice: don't be a fanatic about pure-OOP. If it seems more natural to break out a standard operation as a proceedural module, there's no reason not to do that. And if you're working with a Real Relational Database (postgresql, oracle, etc) think about letting the database do some of the work (the class-to-table mapping popular with a lot of the ORM out there has it's problems -- though it probably does make for some quick prototyping).

        [1] Or some other animal product.

Re: Really Writing Object Oriented Perl
by Jenda (Abbot) on Jun 02, 2007 at 23:07 UTC

    I doubt everyone or even just a sizable group of people here come from the FUNCTIONAL programming background. PROCEDURAL more likely. Please don't confuse the two.

      Just to clarify Jenda's good point, functional programming is a style that avoids state (i.e., variables) and centers around evaluating the value of functions. LISP is a functional language. Procedural programming is written as a list of instructions (segregated into procedures) for the computer to follow, changing state as it goes. C is a an example.

        LISP is a functional language

        Probably more accurate to say that Lisp can be written in a functional style. You also get OO Lisp, and the usual load of procedural code. Much like Perl in fact :-)

        For functional languages look at things like Haskell.

      Yes, 'functional' is an unfortunately overloaded word.

      FWIW when I used the word functional, I meant functional programming a la lisp etc.

      For an introduction to functional style programming in perl, take a look at http://perldesignpatterns.com/?FunctionalProgramming