Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

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

by tilly (Archbishop)
on Jul 28, 2005 at 04:23 UTC ( [id://478815]=note: print w/replies, xml ) Need Help??


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

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.)

Replies are listed 'Best First'.
The beauty of MMD
by Ovid (Cardinal) on Jul 28, 2005 at 17:06 UTC

    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. :-)

        tilly wrote:

        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.

        I'm not sure I follow you here. Are you suggesting that in examples like I provided, the invocants be in different classes? Whenever possible, I really like to minimize the number of classes and creating a new class just to handle a different argument type to a method frequently does not make sense. One example of this would be the constructor:

        my $parser1 = Some::Parser->new($string); my $parser2 = Some::Parser->new($uri_object); my $parser3 = Some::Parser->new($fh_object);

        In that example, with three constructors, each taking a different argument type, we can still return objects in the same class. Class-based dispatching wouldn't make sense there. Did I misunderstand what you were saying?

        Dan Sugalski points to event driven code where different objects generate events and your event handlers are a series of methods whose arguments are the objects generating the events. I shouldn't push the event handling into the objects themselves because they shouldn't care how they're going to be used. Instead, I have a simple GUI class which knows that it's supposed to handle events. This is a common Java idiom and it works very well.

        The main problem I have with MMD is I am frequently more interested in the interface an object provides rather than its type/class.

        Oh, and you'll see that I'm not the one who used the getter/setter example. While it's a reasonable example that fits well with many people's coding styles, I also prefer different names there because the methods are doing different things. When the methods are conceptually doing the same thing, they should have the same name, if possible.

        Update: Whoops! I guess I did use a getter/setter example :)

        Cheers,
        Ovid

        New address of my CGI Course.

      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.

        First, I called him "Ben" without thinking about it. He happens to be a friend of mine, we talk on the phone and calling him Ben seems to be natural. It wasn't intended as making thing "personal."

        As for the rest of your points, argue them with Dan Sugalski :) Incidentally, that link points to a concrete example of something that might satisfy tilly's desire to see a problem for which MMD is suitable.

        Oopsie. The code silently fails.

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

        As I pointed out earlier in my post, my discussion was about both MMD and proper argument handling. To my mind, you can't have the former without the latter. And I agree with your concerns about B&D. I, too, don't like B&D, but to my point of view, properly implemented MMD could let me having sanity checking without forcing any sort of B&D. See Perl 6's ideas behind MMD for examples.

        Cheers,
        Ovid

        New address of my CGI Course.

        Jumping into a fray that isn't mine:

        I think that the point is MMD is usefull and would be nice to have. I'm not sure what your argument agianst that was except that you didn't like his argument. So here is a plain as day example using Perl6 MMD and i'd like to see your example of the same code that is at least as simple.

        multi method name () { return $.name }; multi method name (Str $new_name) { $.name = $new_name; $new_name };

        The return value of the second call is always debatable, but not realy the point here. This is obviously a very simple example, but the point is, anytime your action varies depending on the types of paramters, MMD is a nice trick to have available. BTW Perl6 allows MMD and allows you to still have your old fashion perl5 send me everything in @_ subs too, so you can have your cake and eat it too (whatever that means ;) )


        ___________
        Eric Hodges
          A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-03-28 18:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found