in reply to Re^3: The beauty of MMD
in thread Perl 5's greatest limitation is...?

If you change the problem then yes that is an answer. The point of MMD is one name for a sub that acts differently based upon inputs. The original question was over perl 5 being limited by not having MMD. Which it can be made to do, but your post does not. You may claim that MMD is useless to you, and that is fine, however it makes some tasks quite simple like shown in my post. Your answer is fine and it is probably arguable that any use of MMD can be reformated so that it can be solved without MMD. The same is true for OO, and probably any other single peice of programming or concept, it is however not realy a sound argument agianst anything at all.


___________
Eric Hodges

Replies are listed 'Best First'.
Re^5: The beauty of MMD
by tilly (Archbishop) on Jul 31, 2005 at 01:29 UTC
    The question is not whether any use of MMD can be reformatted so that it can be solved without MMD. The question is whether it is better to do so.

    I happen to believe that it should be very clear what a given subroutine does. That gives me an admitted bias against MMD, because the job of MMD is to make it easy to have subroutines which are ambiguous, they do lots of different things depending on input. However I accept that there are cases where you do need polymorphic behaviour. What I'm not convinced of is that it is worth using MMD to provide that behaviour.

    Depending on the exact problem, I'm happy to not have accessors at all in OO code. Or if you do want accessors, I'm happy to name getters and setters differently. Certainly your example doesn't give me a burning desire to use MMD.

    Now perhaps you don't think, You're adding a lot of complexity and I don't think you're getting much for it is a valid argument. In which case I don't quite know what to say. We are supposed to be in the business of managing complexity, not creating more because it is fun.

    On the other hand perhaps you think that we are getting a lot for the complexity. I don't see the wins as being significant, but we may just have different opinions on that. In which case that is fair, people do not have to agree on everything. Perl always had the attitude that it should be a big language, and people can just pick a subset that is comfortable for them.

    But I'm still puzzled at why so many seem to be so enthused about MMD, and consider it a critical missing figure. Because I obviously don't "get it" at all.

      Perhaps I'm just having trouble following the thread, but I see MMD the other way around. MMD's job is to make it easy to have subroutines which are concrete and unambiguous.

      =item calculate_area The calculate_area function calculates the area of the points passed in. You can pass the points in a number of different ways, but, regardless, you'll get the area back. =over 4 =item * You can pass in a series of points. The function will assume that the shape described is a closed-shape, that is, the first point is automatically repeated as the end point. You can pass in the points as perl6 pairs, e.g.: $area = calculate_area( $x0 => $y0, $x1 => $y1 ); or as two lists of x's and y's: $area = calculate_area( @x, @y ); or as a list of Point objects $area = calculate_area( @points ); =item * You can pass in a Shape object. $area = calculate_area( $shape ); =item * You can pass in an equation, and a beginning x-value and an ending x-value, and the area will be that under the curve. The area may be negative in this case. $area = calculate_area( $equation, $x0, $x1 ); =back Returns: the area of the shape, in square units. =cut
      To me, the subroutine is incredibly unambiguous. It calculates area. It's a nice DWIMmy function that can handle any type of input. However, if I were to maintain this type of DWIMmery, it'd be a minor headache - I'd resort to something like this:
      sub calculate_area { unless ( grep { ref $_ ne 'Pair' } @_ ) { goto \&_calculate_area_pairs; } if (@_ % 2 == 0 and not ref $_[0]) { goto \&_calculate_area_x_list_y_list; } unless ( grep { ref $_ ne 'Point' } @_ ) { goto \&_calculate_area_list_of_points; } unless ( grep { ref $_ ne 'ARRAY' } @_ ) { goto \&_calculate_area_list_of_arrays; } if (UNIVERSAL::isa($_[0], 'Shape')) { goto \&_calculate_area_share; } if (UNIVERSAL::isa($_[0], 'Equation') and @_ == 3) { goto \&_calculate_area_equation; } die "Didn't recognise how you called calculate_area"; }
      And then I'd implement each possibility in a separate function. The interface is simple, and very perlish (DWIM's very well - and can add more DWIMmery later). The code is ugly. MMD handles the ugly part of the code in a very generic manner which means that it only needs to be debugged by the p6 team, not by each developer who wants it. Because I'm quite sure I've got sneaky little bugs in that untested code above.

        Perhaps I'm just having trouble following the thread, but I see MMD the other way around. MMD's job is to make it easy to have subroutines which are concrete and unambiguous.

        I think what tilly is getting at is that MMD can, from a certain perspective, make it harder to see what code is going to be executed.

        This is a general problem as we add more ways of breaking up and abstracting the code. For example with this code:

        do_stuff($x, $y);

        With no modules we know, just by looking at the call, that do_stuff() is defined in this file. We have one place to look, and we can only affect what do_stuff() does by changing that subroutine (or the stuff that subroutine calls).

        use Foo; ... do_stuff($x, $y);

        As soon as we add modules do_stuff() could come from the current file or Foo.pm. Now we have two places to look for do_stuff(), but at least it's only defined in one place.

        use Foo; ... $foo->do_stuff($x, $y);

        Now that we've added objects we need to look at the class of $foo, the name of the method and understand the way the class hierarchy is searched for methods, before we can figure out that it could be defined in Foo.pm, or any of the ancestors of Foo.

        Indeed with calls to SUPER:: what do_stuff() does could be split over several different files and subroutine definitions, and changing any of them could affect what this call does.

        use Foo; # build with MMD ... $foo->do_stuff($x, $y);

        Now with MMD we need to know the classes of $foo, $x and $y, their respective parent classes and understand a more complex method ordering function, before we can be certain of where the bit of code associated with this call lives.

        We have the problem that changing the class hierarchies of the objects in $foo, $x and $y, or adding different variants of do_stuff() can potentially change the ordering of the methods and so change what this particular call to do_stuff() does.

        The recent spirited discussions on method ordering functions that have been happening on perl6-language are an example of how tricky this can be.

        These are, I think, the kind of problems that make tilly question the utility of MMD.


        That said, I like MMD and want it in Perl :-)

        Why aren't I worried? Several reason.

        I spent some time using MMD when I wrote code in Lisp/CLOS some years back. The vast majority of the time it all just worked. While there are many possible routes for unexpected things to happen, they're not a common occurrence in practice as far as I'm concerned. So my experience using MMD took away a lot of my fear.

        Another reason I like MMD is that I find breaking down program flow using polymorphism less susceptible to bugs than breaking down program flow with if/then statements. Since I'm lazy I'd prefer the compiler write my despatch code rather than do it myself. It will probably do a better job and, since it's part of the language core, people won't have to learn what it does.

        The most insidious problem that I encountered was that occasionally changing code changing the method ordering and broke existing code. I'm no longer frightened of that because I produce all my code test-first in small incremental steps. So any problems of this sort will rapidly show up in test failures, which I know will be associated with the last change that I made.

        So, taken on the whole, I find MMD enables me to remove complexity rather than add it in.

        I'm quite sure I've got sneaky little bugs in that untested code above.

        Big ones too (UNIVERSAL::isa).

      For me the definitive "why MMD?" example was one I saw recently in that DSL-in-lisp movie that was making its way around a few blogs a few weeks ago.

      The movie is mostly aimed at showing off lisp's macro abilities, but those to me are pretty old hat - I've been seeing smug lisp weenies praise macros for years - but along the way the programmer casually uses MMD where in perl I'd have to use a bunch of cascading if/elsif blocks or at best a dispatch table. It's not a huge difference, but having seen it in action, it's something I want. Not need, necessarily, but want in the way I really-want-but-can't-quite-justify a new desktop. (It's been a few years; on the other hand, there are other bills that must get paid...)

      Think of MMD as yet another way for the language to get out of your way when expressing the solution to a problem.

      -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/