Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

(tye)Re: Hacking with objects

by tye (Sage)
on Mar 23, 2001 at 20:42 UTC ( [id://66663]=note: print w/replies, xml ) Need Help??


in reply to Hacking with objects

Some good comments. I'd like to stress that OO is quite useful in Perl (it isn't "great OO" if you compare it to OO in some other languages, but it is very useful and overcomes some sticky problems, especially if you are writing a module).

But I'd really like to stress that inheritance is so very often way overemphasized in OO and it should only be used for certain special and fairly rare cases. In Perl's OO, inheritance is especially troublesome and I strongly suggest that you enthusiastically avoid it.

But the dark thoughts kept coming: put that in the destructor method, make that a class variable, don't use inheritance or overloading where an 'if' gets it done in half the time.

Destructor methods are a very powerful tool in Perl OO. If you ever use inheritance to replace an if, I will hunt you down and kill you. But one of the particular advantages to OO when writing Perl is that it allows your modules to be used in multiple parts of the same process without having one part's customizations of the module's behavior stomping on the other part's. So I only consider one of those thoughts as "dark".

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re (tilly) 2: Hacking with objects
by tilly (Archbishop) on Mar 23, 2001 at 21:40 UTC
    What is wrong with using inheritance to replace an if?

    If the test would have appeared in 20 places, I would find it very reasonable to use inheritance to abstract out the check. And if the if would have been a case statement, well eliminating that is exactly what inheritance is for!

    OTOH if the test would have appeared but once, that is a different issue...

      What is wrong with using inheritance to replace an if?

      If the test would have appeared in 20 places,

      I see that you didn't even answer your own question!

      Even if I had 20 ifs and they were all the same test and they all represented a clean bifurcation of a design, I'd still scream at you if your first thought of how to remove the ifs was inheritance.

      If you use only inheritance then you replace:

      sub Widget::Munge { # code block A if( $self->is_blue() ) { # code block B } else { # code block C } # code block D }
      with
      sub Widget::Munge { # code block A # code block C # code block D } sub Widget::Blue::Munge { # code block A # code block B # code block D }
      plus other code to implement the object...

      Now multiply that by 20. Gee, great solution. Now instead of 20 repeated ifs we have 40 repeated blocks of code.

      Oh, I'm sorry, you meant to also abstract out the code in the if blocks as separate functions. Okay, so now we have 40 new functions. What are you going to name them all? Does each of the 40 have a single, clear purpose that it serves well?

      Or are you assuming that each of the ifs also surround identical code? Well, then your problem isn't that you 20 ifs; your problem is that you have 20 duplicated chunks of code. So abstract that out as a function and now we have 1 if and using the sledgehammer of inheritance to squish it is still not the best first choice.

      Even if we decide that we have a case where using two functions in place of one if makes sense, then I'd first consider just storing a reference to the function in the object. If we have a bunch of cases like this and creating another class is warranted, I'd still prefer to have the original object contain a reference to these new objects rather than resorting to inheritance.

      From Advanced Perl Programming:

      Perl supports only [implementation] inheritance. [....]

      Subclassing is not easy, as Erich Gamma et al. say in Design Patterns:

      Designing a subclass also requires an in-depth understanding of the parent class. For example, overriding one operation might require overriding another. An overridden operation might be required to call an inherited operation. And subclassing can lead to an explosion of classes, because you might have to introduce many new subclasses for even a simple extension.
      They suggest using composition instead, a topic we will touch on shortly.
      and
      When C++ came along, I quickly became enthusiastic about a language that supported inheritance, and attempted to implement the widget set in C++. Then when John Ousterhout's Tk came along, I marveled at the ease of creating widgets, even though it was in C and provided all the features that Motif provides (and much more). The Tk architecture used composition, not inheritance.

      If Perl supported other types of inheritance, then I'd be less critical of the use of inheritance in Perl.

      But even Perl's version of implementation inheritance has extra pitfalls beyond those in most languages. But I'll save the details for a meditation since few will benefit from an analysis deep in an old thread.

      So, yes, using inheritance in Perl to remove an if is still likely to tempt me to hunt you down and kill you. (:

              - tye (but my friends call me "Tye")
        I suspect one or the other of us is talking past the other. Or both. Probably both.

        The classic situation where I would hide an if behind a method or function call is for portability. What I would do is have a module that promises a given API. Then when I load or construct objects I would - once - test for which implementation I should use and load that one. From then on I would call my API and the check for what way to do things is hidden.

        This can be done with or without inheritance. Usually it works better without. Consider DBI for a practical example.

        But if my API was one which came down to a situation where the offered API was relatively rich but the number of truly essential methods was small, a clean way to do this is to inherit from an abstract base class and then implement the necessary methods. Conceptually I like to compare this to tie. Now there are implicit "if" tests everywhere, all hidden within inheritance.

        An example of this is LWP::Protocol. Even with all of the usual caveats about inheritance in Perl, this example strikes me as well-designed.

        Yes, Perl could have a better inheritance model. And yes, inheritance is overused and misunderstood. But all that notwithstanding, there are cases where I think it is still appropriate. And keeping there from being a million if/elsif/else cases scattered through the code but instead hiding it in an interface can be one of them.

My first death-threat on Perl Monks ;-)
by frankus (Priest) on Mar 26, 2001 at 14:13 UTC

    Of all the responses this is my favourite. I'm surprised it's not got more votes than my comment.

    If you've read the question 1, I hope you'll see it's not a "how should objects be used" question; it's a "how should I abuse objects.." question, tye's and tilly's comments were more salient for me (FWIW).

    Not to say the others missed the point, I've learnt some new OO good practices, thankyou :-). I've ++ all the comments in a thread, since they're all well written and to see what other folk think of the responses, if people ++ a statement more than I'd expect then I look a harder at the comment, to see if I've missed anything.

    1. For me "Hacking Objects in Perl" means elegantly ignoring OO principles to achieve what I want. I could do neat Objects but not in this job ;^)

    --
    
    Brother Frankus.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://66663]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2024-04-19 12:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found