Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Perl 5's greatest limitation is...?

by Ovid (Cardinal)
on Jul 28, 2005 at 01:20 UTC ( [id://478779]=note: print w/replies, xml ) Need Help??


in reply to Perl 5's greatest limitation is...?

Hmm, I'm hard-pressed to argue that point. If I were to come up with something else, I would argue that the lack of multi-method dispatch is a pretty big problem. Of course, that's sort of cheating because if you get that, it automatically implies proper argument handling and I therefore get two for the price of one :)

Unfortunately, I've seen those who have not had a chance to work extensively with MMD aren't terribly impressed by its benefits. My suggestion to them would be to take a program written in a language which supports this and try to port it to Perl. It leads to monstrosities like the constructor for AI::Prolog::Term:

sub new { my $proto = shift; my $class = CORE::ref $proto || $proto; # yes, I know what I'm doi +ng return $class->_new_var unless @_; if (2 == @_) { # more common (performance) return _new_from_functor_and_arity($class, @_) unless 'ARRAY' +eq CORE::ref $_[1]; } elsif (1 == @_) { my $arg = shift; return _new_with_id($class, $arg) if ! CORE::ref $arg && $ +arg =~ /^[[:digit:]]+$/; return _new_from_string($class, $arg) if ! CORE::ref $arg; return $arg->_term($class) if CORE::ref $arg && $ +arg->isa(Parser); } require Carp; Carp::croak("Unknown arguments to Term->new"); }

That constructor was buggy for a long time because Perl doesn't support MMD. It was very frustrating.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re^2: Perl 5's greatest limitation is...?
by tilly (Archbishop) on Jul 28, 2005 at 04:23 UTC
    If you try to implement a design that relies on MMD without having MMD, you will have difficulties.

    You have not convinced me that designs that rely on MMD are a good idea. Particularly not in a language like Perl where the way people usually use the language will lead to people expecting you not to do that.

    To be convinced I'd need to see a problem which interests me that I have trouble solving without MMD, which has a very nice solution using MMD that I think would not pose a maintainance problem. I've yet to see such a problem. (Admittedly I also haven't looked very hard.)

      tilly wrote:

      You have not convinced me that designs that rely on MMD are a good idea. Particularly not in a language like Perl where the way people usually use the language will lead to people expecting you not to do that.

      Hmm, that's a rather interesting way of putting it. Let's play with the wording a bit and see if we can clear that up, shall we?

      You have not convinced me that designs that rely on closures are a good idea. Particularly not in a language like Java where the way people usually use the language will lead to people expecting you not to do that.

      While certainly not an exact quote, that's pretty darned close to a rebuttal a Java programmer gave me in response to my arguments about the merits of closures. No offense Ben, but those two sentences are orthoganal to each other. Just because people aren't used to X doesn't mean that X is not a good idea.

      Now that we have that out of the way, let's consider MMD. MMD should not be overused, but when it's necessary, it simplifies the code and is a better solution than a bunch of similarly named methods or forcing the programmer to write code to simulate it. However, MMD and proper argument processing go hand-in-hand, so much of the following assumes we're talking about both.

      For example, if you look at how dispatch tables are frequently implemented in Perl, you'll find that they're often used to dispatch on type. Thus, the programmer has to write some code similar to this:

      my %dispatch = ( Foo => \&_foo, Bar => \&_bar, Baz => \&_baz, ); sub process { my ($self, $thing, $data) = @_; my $type = ref $thing || ''; my $method = $dispatch{$type} || die "Can't find method ..."; $self->$method($data); }

      That, of course, it ugly, but it's a lot less ugly than the faux switch statements or if/elsif/else chains people come up with (and less error prone, too). To compare with MMD:

      multimethod process (Foo $thing, String $data) { ... } multimethod process (Bar $thing, String $data) { ... } multimethod process (Baz $thing, String $data) { ... }

      Not only is that shorter, it's more likely to be correct. Forcing me, the programmer, to write code to handle a common idiom that so many modern languages never have to worry about is silly. Heck, how many times have we seen the following bug?

      sub name { my ($self, $name) = @_; $self->{name} = $name if $name; return $self->{name}; }

      Now, if you need to clear someone's name, it's very difficult to do. That bug is virtually impossible to write when using MMD. What a beautiful thought. An entire class of bugs eliminated. (Of course, MMD introduces a completely different class of bugs, but in my experience, they bite far less often.)

      And let's not forget that MMD potentially allows compiler optimizations that aren't possible when dealing with all of the potentiall buggy programmer alternatives. And while we're on the topic of optimizations, notice that traditional Perl code requires two sub calls for the dispatching instead of one. Perl's subs are slow enough that this could be a significant performance bottleneck on some systems. I've been hit by this and working around it can be very painful.

      However, let's take a look at my dispatch code. If I want to add an extra event, I add another entry to the dispatch table. But what happens when someone does this?

      $object->process($foo, $data1, $data2);

      Oopsie. The code silently fails. Perl's poor argument handling strikes again! However, if I need to actually allow that, my dispatch code can get awfully ugly. With MMD, that can easily throw a nice, fatal error, letting the programmer know that no such method exists. Otherwise, I just write another method. Nice and easy either way.

      And while we're thinking about argument handling, I see (and have written) plenty of code which doesn't verify the number arguments to a method. In fact, this is a debate that regularly comes up in the Perl community: how much sanity checking is required? Many hackers do very little checking and, if we're really lucky, they have test suites to catch stuff. Some put sanity check everything and then moan in horror about how slow their system is.

      Guess why Java programmers don't debate this too much? Because, ironically enough, in the case of MMD and proper argument handling, they have the language doing something that the programmer shouldn't be forced to do.

      PS: When you show up for OSCON, let me know and I'll buy you a beer. Or you can buy me one. Or four. I know how to dispatch them properly.

      Cheers,
      Ovid

      New address of my CGI Course.

        First of all, as was already pointed out, I am not arguing that multi-methods are necessarily bad. Just that you have not convinced me. I further went on to say what would be required to convince me. The fact that this argument can be used by someone else with regards to something that I am convinced is good is not a refutation of that form of argument. No number of examples of people with mistaken opinions will convince me that it is a bad idea for people to try to form their own opinions. In fact no number of examples where I have had a mistaken opinion will convince me that I shouldn't try to have my own opinions!

        Now I see what you're saying in your example, but I have several major caveats.

        First of all let's separate the need for a dispatch mechanism from the desire for multi-method dispatch. Much of what you've just said for multi-method dispatch by type works perfectly well already in Perl if you're dispatching by class using OO. Arguing for how great multi-method dispatch would be using examples where OO dispatch suffices is not going to convince me. You don't need to convince me that there is a need for built-in dispatch mechanisms. You need to convince me that there is a need for complex built-in dispatch mechanisms.

        Remember that I already suspect that a basic maintainance problem with heavily factored OO code is that there is an implicit if in every method call, making the complexity of OO code higher than procedural code of similar length. I am concerned that making the dispatch potentially more complex makes the complexity higher still. In particular I had this concern from descriptions of Perl 6 has had rules to try to figure out a type if nothing matches exactly. When I read descriptions of how it does that, I'm often left wondering how often it would wind up dispatching somewhere I don't want it to dispatch, and how often I would want an error but wouldn't get one.

        Now you used one example where it seems to make sense to dispatch based on number of arguments. And that is an accessor which plays setter and getter. However I have another solution to that problem which I like a lot. And that solution is name your setters and getters differently! A really cute idiom for this in Ruby does like this. If you name your getter bar, then you name your setter bar=. Then Ruby has a nice piece of syntactic sugar where you can write foo.bar = baz; and it automatically knows to call your bar= method. (Ruby has another nice piece of syntactic sugar where it will autogenerate acceptable default accessors for you very easily, but I digress.)

        There is a basic choice here. You can either try to have a complex dispatch method to allow you to overload a method with many different meanings. Or you can have a straightforward dispatch method and have a number of similar (but very distinct!) methods. My natural inclination is towards the latter. (This would be one of the reasons that I am not a fan of multiple inheritance...)

        Now lets move on to hand-rolled dispatch mechanisms. As I've already noted, Perl has a working OO dispatch mechanism. Therefore if I write a hand-rolled dispatch mechanism, my needs are likely to be rather customized. For one thing I'm almost always dispatching on value. Secondly I sometimes have a customized dispatch table - you can pass the dispatch table into the function. Thirdly I frequently want to customize the "fallback" behaviour. Fourth I usually have a non-trivial lookup to figure out what I'm dispatching on.

        Now I see how a smart MMD system could satisfy some of those needs. But I don't think (I may be mistaken, of course) that proposals for Perl 6's MMD system would be flexible enough to handle the cases where I want to write a customized dispatch system in Perl 5.

        Now let's wrap up loose ends.

        The optimization note doesn't matter to me. Perl is simply not a bottleneck for the kinds of things that I want to do with it. (Usually the bottleneck is the database.) And if I really wanted performance, Perl wouldn't be the tool that I'd reach for. That isn't about to change any time soon.

        Please don't take any of what I've said as a slam on Perl 6. My understanding of Perl 6 says that I can ignore whatever I want to ignore. I'm fine with not using a capacity for MMD.

        And about the PS, I'm not only hoping to exchange a beer or three, I'm hoping that you have some good ideas on where to find the best parties. :-)

        Let's play with the wording a bit and see if we can clear that up, shall we?
        If we're going to play that game, I'll have a go:
        ... when it's necessary, it simplifies the code and is a better solution ...

        Seems to me that in cases where it's necessary, it doesn't just simplify the code and make a better solution — it makes a solution (and the code) possible. That's what "necessary" means.

        More to the point, you completely ignored the part where tilly said (and which I second):

        To be convinced I'd need to see a problem which interests me that I have trouble solving without MMD, which has a very nice solution using MMD ...

        (Aside: why did you call tilly "Ben"? Seems to me that is just making the argument unnecessarily personal — sort of a virtual "grabbing your opponent by the lapels".)

        But anyway...

        MMD potentially allows compiler optimizations that aren't possible when dealing with all of the potentially buggy programmer alternatives.
        What compiler optimizations are you thinking of? Seems to me there are precious few possible compiler optimizations in dynamic languages relative to their static brethren.
        $object->process($foo, $data1, $data2);
        Oopsie. The code silently fails.

        That is an argument for prototypes on methods, not for MMD specifically.

        This is a debate that regularly comes up in the Perl community: how much sanity checking is required?

        I fall in the camp that believes perl should stay out of my way unless and until I ask otherwise. Perl is not a B&D language. Strict is off by default.

Log In?
Username:
Password:

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

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

    No recent polls found