in reply to perl6 & OO

I won't comment on the Perl 6 00, but I couldn't help but notice this comment:

I see [perl5's object system] at as very elegant and minimalist.

Perl 5 OO is great, but once I started working with other OO languages, I realized that there are some features that are missing.

I want to be able to do method overloading based on signatures. That's not build into Perl. In Java, it's simple"

public void foo(int x) { // do something with x } public void foo(int x, int y) { // do something with x and y }

In Java, the number of arguments and their types will determine which method is called. In Perl, you generally have to build your own dispatch method (there are CPAN modules to do this) and this is prone to bugs.

I would like a clean separation of class and instance data. In Java, I can simply use the "static" keyword.

Want private variables and methods? Use the "private" keyword. They're not too hard to do in Perl, but that seems like an accident. I frequently use anonymous subs attached to lexical variables to get private methods, but that's not intuitive to a new Perl programmer.

Protected methods in Java can only be used by the class or its subclasses. Trying to prevent a calling program from using them is fairly easy, but it's not built in to Perl.

And the "canonical" example of a Perl constructor:

sub new { my ($class, %data) = @_; bless \%data, $class; }

Now anyone who wants to violate encapsulation can do so by reaching directly into the object. Also, you lose the benefit of using "strict".

This is not to say that Perl's OO is awful. Multiple inheritence can be good (if you really need it -- delegation is typically better), but Java's "interface" hack doesn't allow them to solve their single-inheritance limitation.

Cleanly building a bunch of accessors and mutators on the fly in Perl is a breeze. Not so for Java. You typically have to cut-n-paste the code (if I recall correctly, EJB can solve this problem).

Perl's OO is very easy to use and I quite like it, but it does have some limitations and people should be aware of them.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
2Re: perl6 & OO
by jeffa (Bishop) on Feb 19, 2004 at 14:14 UTC

    When you try to code Perl like Java, yes, you run into the problems you mention. But i never try to code Perl like Java ... that's why we got Java! ;)

    Personally, i think that Perl's OO IS kinda awful, but it works great for me and my small team that uses it. My friend who codes Java with a large Java team still has nightmares to deal with, everyday day. Is that Java's fault? I don't think so ... i think the people with whom you work matter more than the tool you choose. And, generally speaking of course, if you work with some not-so-talented people, then maybe your team should be using Java instead of Perl. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Re: perl6 & OO
by flyingmoose (Priest) on Feb 19, 2004 at 14:08 UTC

    Exactly. I'd like methods give compile errors if their arguments if they are the wrong type. Even using mechanisms like strict, etc, Perl is a little dangerous when it comes to OO syntax. When I'm writing a straightforward non-OO app, this is fine, and I can deal with it, but when I really want objects, I want Perl to understand them and enforce them, rather than allowing them to be scalars. I think this could be accomodated for in the oft-unused Perl message-signature feature, which right now only takes basic types.

    Also, it's really odd what determines when a class has a certain method. For instance, if I have a "$program->run" and a "$dog->run" I don't want to be able to call $foo->run() and have it work with both dogs and programs. I want method overloading. I want cleaner inheritance and things like "super()". I'd like to be able to specify virtuality and non-virtuality.

    Having a dog run and a program run? This does not make sense. Chewbacca lives on Endor, and this does not make sense. Therefore we must have more strongly-checked OO.

    I started my OO life learning C++ and Java, grew to love Java, grew to hate Java, but it wouldn't be bad if Perl became a little more mainstream in it's OO. Just don't repeat Java's failings -- inconsistant API, lack of multiple inheritance, exception hell, etc. Perl already has a leg up since it has a much stronger base library -- so a little cleaner OO syntax to go with that library, that would be great.

    My only OO heresy is that I despise "getter and setter" methods. Maybe that's not heresy, maybe those methods are against the spirit of message passing (I think they are). Anyhow, Perl doesn't have to mandate style as far as java does, where a programmer is cast down for making a public variable. It should, however, start to treat objects as though they have types.

      I think this could be accomodated for in the oft-unused Perl message-signature feature, which right now only takes basic types.

      Apoc. 6 went through a total revamp of subroutines signatures. You can still use them like:

      sub foo { my ($bar, $baz) = @_; . . . }

      If you really want to, but if you did that, you'd be missing out on a lot of really cool stuff. I'm not so sure I personally want rigidly-enforced typing, but some of the signatures make calling conventions easier and make it obvious when we've called something incorrectly. At the same time, little flexibilty is lost over doing a complete check of @_ before we get to the actual code of the subroutine.

      Type systems applied to objects is one way to solve the problem of $dog->bark vs. $tree->bark, but I'm not sure if it's the best. Delegation and Traits (both widely talked about in Perl6 development) are potentially much better.

      My only OO heresy is that I despise "getter and setter" methods.

      Hardly heresy. Having lots of accessors and mutators (i.e., methods which provide direct access to private data) is a sign of poor class design. I won't go as far to say that they should be absolutely forbidden. Whenever I enter such a debate, I hear this Drunken Scottish Object Programmer saying:

      Ya can't just spread aaaccessors and muuutators all over your class design there ladie. You're screwwen the whole point!

      But then again, maybe I should get the voices in my head checked out.

      ----
      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

      For instance, if I have a "$program->run" and a "$dog->run" I don't want to be able to call $foo->run() and have it work with both dogs and programs.

      What's wrong with each providing a run method? If I'm iterating over a collection, I will not be putting both a program and a dog in the same collection. If I do, I probably have a serious confusion in my code. But what if I have a list of animals?

      foreach my $animal (@animals) { $animal->run; }

      That's what polymorphism is all about. Fortunately, that's very easy to do in Perl. Perl does provide many of the most useful OO features in Perl. What it lacks is easy to use encapsulation.

      As for getters and setters, can you think of any popular language with OO features that doesn't allow them? This isn't a Perl issue as far as I know. It's an issue with programmers treating objects as structs with methods calls. In fact, this is not a Bad Thing, so long as it's used appropriately.

      I think this could be accomodated for in the oft-unused Perl message-signature feature, which right now only takes basic types.

      Can you provide an example? I'm curious. If you're referring to prototypes (I don't think you are), then you should be aware that those are checked at compile time while method dispatch is resolved at runtime, thus making prototypes useless on method calls.

      Cheers,
      Ovid

      New address of my CGI Course.

        What's wrong with each providing a run method?

        Nothing. However, there is a LOT wrong with weakly typed variables and not requiring arguments to be of certain types, just because they all have 'run' methods does not mean I should be able to interchange programs and dogs. That's just asking for trouble.

        As for getters and setters, can you think of any popular language with OO features that doesn't allow them?

        I think you meant to say, is there any language that absolutely requires them? In which, no. The argument was in reference to prior comments of Perl OO's system being flexible. My comment was, essentially, as long as Perl doesn't do anything stupid like require getter/setter methods (it won't), I'm ok with a more rigid object structure.

        Can you provide an example?

        Dog::chewPantleg(Person ted) { # implementation }

        In the above example, you can't have a Dog chew another Dog's pantleg. It's enforced that the argument is a person.

        If you're referring to prototypes (I don't think you are)

        I am, however weak the current implementation is, that's what I'm talking about. Perl seems to allow OO implementation (a little better than how GTK might implement pseudo-OO in C), but it does not embrace it in spirit. I'm not saying it should be enforced, but it should be embraced.

        Then you should be aware that those are checked at compile time while method dispatch is resolved at runtime, thus making prototypes useless on method calls.

        I'd like to see that change in Perl6. Maybe it's a pipe dream, but it seems to be a requirement for clean polymorphism.

Re: Re: perl6 & OO
by demerphq (Chancellor) on Feb 19, 2004 at 15:34 UTC
    sub foo { my $self=shift; if (@_==1) { // do something with single arg } elsif (@_==2) { // do something with two args } }

    Point is that in a language like perl we can a) simulate the behaviour of java, b) we can provide behaviour that java plain and simple cant provide.

    Incidentally what do we do with

    foo(@bar);

    Which version of foo should be called? Should the langauge simulate the if that i put inside the sub above? If so what do you do when you have a situation that doesnt make sense? For instance if @bar contains 3 vars. What should it do? Call the var version and ignore the third? Die?


    ---
    demerphq

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


      Your first example shows a limitation with Perl. By being forced to use a conditional to deal with the number of arguments, we automatically introduce more chances for bugs because every conditional is an opportunity for bugs to arise. The fewer conditionals you have, the fewer bugs you're likely to have. Obviously you can't avoid them, but fewer should be needed with proper OO design. With Java, the method called is automatically the one you want. Not so with Perl. What happens when you want to handle one, two, or three arguments with different behavior if the optional third argument is a string or a float? In Java, that's four methods. In Perl, typically it's an ugly if/else construct with the logic handled in the method or then dispatched to to the other four methods.

      As for the case of foo(@bar), Java wouldn't handle that the way a Perl programmer is expecting because it doesn't turn that array into an argument list. Instead, it would dispatch it to a method that takes an Array object. To simulate that in Perl, create an array object or pass the array by reference.

      This also brings up a strength of Perl that's a limitation in Java and many other languages. In Perl, are functions and methods are implicitly variadic (they take a variable number of arguments). If you code your methods right, this can be useful, but it can also mean that arguments fall off the end.

      Because of Perl's behavior, strange bugs are available. Consider this:

      sub foo { return @foo } $object->bar($wibble, foo());

      Some people might be fooled into thinking they're passing at least two arguments. However, if @foo is empty, then &foo will return an empty list and when the list is flattened into the argument list of &bar, you'll only have one argument:

      $ perl -MData::Dumper -e 'sub foo {@a}; bar(1,foo()); sub bar {print D +umper \@_}' $VAR1 = [ 1 ];

      Again, I love Perl, but the lack of useful prototypes can really hamper the language at times.

      Cheers,
      Ovid

      New address of my CGI Course.

        Your first example shows a limitation with Perl. By being forced to use a conditional to deal with the number of arguments, we automatically introduce more chances for bugs because every conditional is an opportunity for bugs to arise.
        I have two problems with this: 1. what's going to cause more errors, a condition or copying whole methods? 2. if a method does different things with different arguements, why is it called the same thing?
        The fewer conditionals you have, the fewer bugs you're likely to have.
        The less code you have the fewer bugs you're likely to have surely?
Re: Re: perl6 & OO
by Benedictus (Beadle) on Feb 19, 2004 at 16:20 UTC

    Ovid wrote:

    Protected methods in Java can only be used by the class or its subclasses. Trying to prevent a calling program from using them is fairly easy, but it's not built in to Perl.

    Actually, protected methods in Java can also be used by classes in the same package. Nevertheless, your point is well-taken. I was working on a project recently where I wished that I had some way of faking protected (and, yes, I am aware of Class::Fields, but that wasn't an option at the time--long story).

    Benedictus

      "Protected" has a different definition in pretty much every langauge that has it as a feature. It all encompasses the idea that objects that are friends get extra operations on each other. In Perl, you can emulate the feature using caller by checking the package of the code that called you. It's a flexible solution (you get fine-grained control over who gets to call you and who doesn't), but it can get sloppy fast.

      ----
      : () { :|:& };:

      Note: All code is untested, unless otherwise stated