Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Clever vs. Readable

by Anonymous Monk
on Aug 09, 2008 at 17:08 UTC ( [id://703286]=perlmeditation: print w/replies, xml ) Need Help??

So, I'm looking at some Perl Books (Perl Best Practices By Damian Conway and Effective Perl Programming by By Joseph N. Hall and Randal L. Schwartz) and I found two encountered opinions on how good code should look like. In particular, both adressed (casually?) the following line:

$result = [$a=>$b]->[$b<=$a];

This returns the lowest of the two values.
Let's see what they said about it!

* Effective Perl:

"This wonderfully symmetrical one-liner contributed by Phil Abercrombie returns the lesser of $a and $b.
It can be written with less wasted technology, but then it isn't nearly as pretty:

$result = ($a, $b)[$b <= $a]"

* Perl Best Practices:

"[...] The syntactic symmetry is very elegant, of course, and devising it obviously provided the original developer with a welcome diversion from the tedium of everyday coding. But a clever line of code like that is a (recurring) nightmare to understand and to maintain, and imposes an unnecessary burden on everyone in the development and maintenance teams.

[...] However, it's also possible to write that same expression in a way that's so obvious, straightforward, and plain-spoken that it requires no effort at all to verify that it implements the desired behaviour:

use List::Util qw( min ); $result = min($a, $a);

It's not "clever" and it's even marginally slower, but it is clean, clear, efficient, scalable, and easy to maintain. And that's always a much better choice."

So whose side are you on?

Note: I changed the variable names so that both books are consistent with each other.

Replies are listed 'Best First'.
Re: Clever vs. Readable
by BrowserUk (Patriarch) on Aug 09, 2008 at 17:36 UTC

      "hands down fastest" certainly. Fairly simple and reasonably clear I'd agree. As simple, clear and reliable to code as min? Not a chance.

      For trivial variables the ternary operator is ok. But, as soon as any indirection or any other complication in obtaining the values is required the ternary solution becomes unclear and starts to lose its speed advantage. If calculating the values has side effects the ternary version simply isn't tenable.


      Perl reduces RSI - it saves typing

        1. I said "I prefer".

          You are of course free to code as you choose, but don't invoke the justifiction of reliability.

          The day I cannot correctly code my $min = $a < $b ? $a : $b; is the day I'll go looking for a CPAN module to do it.

          At the same time I'll go looking for something to help me with:

          if( $a < $b ) { ## Do what is required when $a is the lessor } else { ## Do what is required when $b is the lessor }

          Any thoughts? Maybe you'd code that as if( min( $a, $b ) == $a ) ...?

        2. If I've to demolish a wall, or drive a nail, I'll reach for a hammer.

          But when I've a nut to crack, it stays in the toolkit.

        3. And if you want to play what-if games. What if $a and $b are overloaded objects?
          #! perl -slw use strict; use X; use List::Util qw[ min ]; my $a = X->new( .5, .5, .5, 1 ); my $b = X->new( .7, .9, .4, 1 ); print $a < $b ? 'a is the lessor' : 'b is the lessor'; print "\n-------\n"; print min( $b, $a ); __END__ [ 0:38:13.97] c:\test>junk3 a is the lessor ------- Argument "X=ARRAY(0x1824550)" isn't numeric in subroutine entry at c:\ +test\junk3.pl line 10. Argument "X=ARRAY(0x2251a4)" isn't numeric in subroutine entry at c:\t +est\junk3.pl line 10. X=ARRAY(0x1824550)

          Even ignoring the warnings, did min() get the answer right? And if it did, was it for the right reasons or just some fortuitous accident that'll come back and bite once it goes into production?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I find $a < $b ? $a : $b clearer than min ($a, $b). The former in unambiguous, the latter uses an ambiguous abbreviation. It's likely to return the minimum of both values, but perhaps it returns $a - $b, or (-$a, -$b). There's no doubt in $a < $b ? $a : $b, but there's some doubt in min ($a, $b).
          A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Clever vs. Readable
by FunkyMonk (Chancellor) on Aug 09, 2008 at 17:15 UTC
    There's an awful lot of TheDamian's opinion in PBP that I disagree with, but in this case he's absolutely spot on.

    Clarification: What I meant by the above was that readable beats clever every time. I didn't mean to suggest that min() should be used to find the minimum of two values. I'd use the ternary operator just as BrowserUK suggested.

      but in this case he's absolutely spot on.

      spot on? nightmare? so what does he say about the Schwartzian transform? hell of a nightmare, I guess. He's not spot on choosing a too simple construct to make an argument of readability vs. maintainability. A perl code maintainer needs a training in TIMTOWTDI, and this one is a good piece of code for that.

        The Schwarzian transform is a standard and widely used Perl idiom. This "min" example is neither of those things. You can't really compare them.

        While Perl programmers do need to understand TIMTOWTDI, they also need to understand that some of those ways are rarely appropriate. This is indeed a great example to teach them that with -- precisely because it's so unreadable. It's a great example of OWTDI that IMO few experienced programmers would seriously consider for use in production code.

        (FWIW, IIRC PBP has nothing against the ST but recommends that it be preceded by a comment identifying the construct.)

Re: Clever vs. Readable
by swampyankee (Parson) on Aug 09, 2008 at 17:23 UTC

    I'm voting for readability, in agreement with Dr Conway. Frequently, code maintenance is assigned to the programmers with the least experience in a language, so terseness is not clever. I've been handed code to maintain in COBOL and PL/1, never having worked in either, and I had never even read a book about COBOL before.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc

Re: Clever vs. Readable
by TGI (Parson) on Aug 09, 2008 at 17:46 UTC

    Readable is best.

    The min example is best if you might need to add extra elements to the list.

    Otherwise, BrowserUK has the right answer.


    TGI says moo

Re: Clever vs. Readable
by zentara (Archbishop) on Aug 09, 2008 at 18:14 UTC
    Don't forget the ultimate in readability, clunkiness, and lack of cleverness: (for new programmers)
    my $min; if( $a <= $b){ $min = $a}else{ $min = $b }

    I'm not really a human, but I play one on earth Remember How Lucky You Are

      Yeah, but what happens when this simplistic (not simple) approach is taken in the wild is that the if/else grows into a 300 line if/elsif and the else to catch fail cases never seems to be there. I'm going through this again at work because a very experienced and generally intelligent manager there would rather do an open-ended if/elsif tree than a hash lookup, "Because it's easier to read."

      In that case, I'd prefer ALGOL:
      min := IF a < b THEN a ELSE b FI;
      (It's a long time since I last coded in ALGOL, so I might have details of the syntax not correct).
Re: Clever vs. Readable
by EvanK (Chaplain) on Aug 09, 2008 at 19:05 UTC
    Using the "Obfuscation" section of PM as an example, there are many of us that consider it an art as well as a craft. As such, they both have their place.

    Perl as an art

    Anything can be an art if you're good enough at it, and coding is no exception. This is more coding for coding's sake, or to keep one's skills honed during downtime, that allows us to create (and appreciate) truly clever obfuscated code. It's not meant for fully functional projects or production environments.

    Perl as a craft

    In this case, readability is key. With anything useful you build, it is very likely that, at some point, someone other than you will be maintaining it. In these cases (most of the time), you want to use an extra several lines of code to clearly illustrate what you're doing and how.
Re: Clever vs. Readable
by Perlbotics (Archbishop) on Aug 09, 2008 at 22:40 UTC
    Considering the poor maintainer (probably oneself), I would vote for readability most of the time. However, shorter code sometimes executes faster (the OPs example probably not). E.g., I think of something with implicit loops like map{...} which gave me some problems decoding when I was a Perl beginner. If terse code is a must, proper commenting is 'more' mandatory. Consider this:
    $result = ($a, $b)[$b <= $a];  # minimum ($a, $b)
    Less than 20 additional characters read in a fraction of a second helps to save some dozens seconds decoding and the uncomfortable feeling to have something missed. From my point of view, clever is okay when there is a gain, be it speed of execution or degree of obfuscation.
Re: Clever vs. Readable
by JavaFan (Canon) on Aug 09, 2008 at 20:57 UTC
    I'd write either:
    $min = $a < $b ? $a : $b;
    or
    $min = $a; $min = $b if $b < $a;
      $min = $a; $min = $b if $b < $a;
      Not only that—if you change $b < $a to $b < $min in the second line, then you're most of the way to addressing the problem with (I think) all the other non-min solutions so far, namely, that they don't handle more than two elements!

      (I sure do love that [ $a => $b ]->[ $b <= $a ] one, though—so much so that, when I heard about it here, I ran out and got Effective Perl just to see if it had more like that. Since the rest of the advice was good, rather than pain-on-the-maintenance-programmer-inflicting, I guess that I have to stick with the obfuscated Perl section here.)

Re: Clever vs. Readable
by jdrago_999 (Hermit) on Aug 10, 2008 at 16:21 UTC
    What about:
    my ($min) = sort( $a, $b );

      Only this sorts alphabetically. And it's complicated to change the sort type because $a and $b are lexical variables here.

      Apart from that, it looks rather clever, too.

        You are absolutely correct. My bad :)
Re: Clever vs. Readable
by shmem (Chancellor) on Aug 09, 2008 at 23:00 UTC
    So whose side are you on?

    On either side. Readability wins Ok, but this piece of code is not too complex, and it provides a good training to anybody who doesn't get at a glance what is meant. A benefit to any maintainer.

Re: Clever vs. Readable
by dokkeldepper (Friar) on Aug 11, 2008 at 05:29 UTC

    As for me, the point in this is not so much the "cleverness". It is merely that the example from EP gives one another perspective to a trivial problem, that may be useful in other places.

    Both approaches have their merit, however their context is totally different. PBP gives advice how to write maintainable progams, EP teaches idioms and ideas on perl.(I own both books, btw)

Re: Clever vs. Readable
by ikegami (Patriarch) on Aug 09, 2008 at 17:28 UTC

    Since only one of the three is actually correct, I'll pick that one.

    Trying to be clever doesn't help.

      dems fightin' werds. pleez explain.
        <= is not documented to return 1 when true.

        Two return a max result. I'll leave you to guess which one is correct.

        The ternary variant suggested elsewhere suffers somewhat from the same exposure to simple coding errors, especially if the value calculations are not trivial or the size of the set of values being tested is increased.


        Perl reduces RSI - it saves typing
Re: Clever vs. Readable
by Anonymous Monk on Aug 09, 2008 at 17:56 UTC
    Example is so short that it makes no difference (if you call it $min, not $result).
Re: Clever vs. Readable
by John M. Dlugosz (Monsignor) on Aug 10, 2008 at 05:01 UTC
    What's wrong with
    $result = $a ⌊ $b;
    
      Some reasons why it's wrong in my opinion:
      1. I've no idea what vertical bar with a small hook to the bottom right means. It's certainly not a common math symbol. (At least, not on its own. It's a "left floor" symbol, usually used together with a "right floor" symbol, indicating the expression in between is rounded down to the nearest integer).
      2. It's a symbol that doesn't display well in my urxvt. And even if it did, it will be awkward to enter in my editor.
      3. It doesn't work in perl5.10 or earlier.
        I was aluding to this tongue-in-cheek article I had just posted. I think it's a more common symbol than, say, @list».*foo, which is actual Perl 6. At least it has precedent, rather than being something totally new.

        What is a "urxvt"?

        After posting, I noticed that it did not show well in the font my browser chose for it. The hook is too small and it is easily confused with a solid vertical bar.

        So assuming font issues were taken care, what do you think of seeing ⌈$x⌉ to mean round up to an integer using ceiling semantics? Even the well-known trunc is not known at a glance to have floor or toward-zero semantics while the synonym ⌊⌋ would be obvious.

        Even more so in domain-specific notation: why invent a legal identifier name when a symbol or notation is already in use with the intended meaning?

        —John

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://703286]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-20 06:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found