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

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.

Replies are listed 'Best First'.
Re^7: The beauty of MMD
by adrianh (Chancellor) on Jul 31, 2005 at 17:11 UTC
    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.

Re^7: The beauty of MMD
by chromatic (Archbishop) on Jul 31, 2005 at 07:26 UTC
    I'm quite sure I've got sneaky little bugs in that untested code above.

    Big ones too (UNIVERSAL::isa).