Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

What is clear code ?

by mandog (Curate)
on Apr 29, 2002 at 01:56 UTC ( [id://162739]=perlquestion: print w/replies, xml ) Need Help??

mandog has asked for the wisdom of the Perl Monks concerning the following question:

In node this node ovid very kindly points out a couple of my silly mistakes. He corrects my code and offers another clearer sub. Ingrate that I am, I'm not sure the new sub is acutally clearer....:
sub Ovid_Clear_MakePtag{ my $fixme = shift; # take in our parameters return join "\r\n", # join with newlines map { "<p>$_</p>" } # wrap each line in <p></p> tags grep { /\S/ } # must have at least one non-whitespace + character split "\r\n", $fixme; # break apart on the newlines } sub MakePtag{ chomp(my $fixme = shift;) # take in our parameters $fixme=~s|(\r\n)|</p><p>|g; # replace all \r\n with <\p><p> $fixme = "<p>$fixme</p>"; # Add beginning and ending tags return $fixme; }

In the new version there are 6 concepts to understand (shift,join, map,split, comments within an expression, return) 5 lines and one relatively long expression.

In the old version, there are 5 concepts (shift,chomp,s///, interpolation, return) and four lines with four pretty simple expressions.

Part of the issue is that I'm more familar w/ the original 5 concepts than ovid's new ones. However, I'm guessing that most people find it easier to read several short expressions instead of one long one...

Am I missing something here?



email: mandog

Replies are listed 'Best First'.
Re: What is clear code ?
by tadman (Prior) on Apr 29, 2002 at 02:17 UTC
    It's not necessarily the best teaching example due to the complexity of it all, but it does show how Perl can work. The "chained" function system is often very useful in data-translation exercises, such as this.

    It might be a little tidier as such:
    sub Clear_MakePtag { return join ("\r\n", map { "<p>$_</p>" } grep { /\S/ } split ("\r\n", my ($fix) = @_) ); } sub MakePtag { my ($fix) = @_; $fix =~ s!\r\n$!!s; $fix =~ s!\r\n!</p>\r\n<p>!g; return "<p>$fixme</p>"; }
    Cosmetic mostly, but since this is about clarity. The chomp call seems kind of strange since it takes off $/, which is OS specific, right? Better to just say what you mean, I would think.

      update: In the original node, I'm probably not as clear I should be that much of the second sub is ovid's

      Yes, while the chomp better than the no chomp, it is not perfect. If the string is something like "asadf\r\n" and the OS is \r\n orriented, the chomp gives us "<p>asdf</p>" instead of "<p>asdf</p><p></p>". If we are processing the string on a \n orriented OS, We are out of luck...

      If I understand  perldoc perlre the "/s" or "!s" at the end of the regular expression means "Treat string as single line. "

      However, in tadman's node, I'm not getting how s/\r\n//s ( or s!\r\n!!s ) means "take off the \r\n at the end of the string" ???



      email: mandog
        tadman said:
        $fix =~ s!\r\n$!!s;
        Notice the '$' mark in the line: it anchors the '\r\n' to the end of string. Meaning, replace \r\n only if it appears as the last thing in the string.
Re: What is clear code ?
by chromatic (Archbishop) on Apr 29, 2002 at 05:20 UTC
    Maybe it helps to consider code clarity algebraically. While it's possible to write 2x = x^2, if you want to solve the equation, you need to isolate your variables on one side or the other. Maybe I'm stretching to make a connection to idioms, but I find the second of these pairs much clearer:
    $i = $i + 1; $i++; $i = $i + $i; $i *= 2;
    Unfamiliarity with Perl's list-processing features does tend to obscure the intent of Ovid's code somewhat, but I can follow it without the comments. (I'd argue it would be clearer with a single comment that said "strip empty lines, wrap paragraphs marked by newlines in paragraph tags".)

    I'm not completely satisfied with either -- it's not clear why "\r\n" is used instead of $/, though Ovid's has a distinct advantage of the <p>$_</p> construct.

Re: What is clear code ?
by abstracts (Hermit) on Apr 29, 2002 at 02:22 UTC
    The 2 programs listed are not equivalent. If you want to rephrase Ovid's example to match your example, it would be something like:
    sub Ovid_Clear_MakePtag2{ my $fixme = shift; # take in our parameters return join "", # join with nothing map { "<p>$_</p>" } # wrap each line in <p></p> tags split "\r\n", $fixme; # break apart on the newlines }
    Or even:
    sub Abstract_Clear_MakePtag{ my $fixme = shift; # take in our parameters return "<p>" . join("</p><p>", split "\r\n", $fixme) . "</p>" }
    which uses 2 concepts: split and join (really one concept).

    Would this make a good "clear" example?

    As for my opinion, I'd go with your example being the clearer of the 3 examples so far.

Re: What is clear code ?
by clintp (Curate) on Apr 29, 2002 at 02:25 UTC
    Don't feel bad. Strictly on readability, I actually like yours better. Not necessarily because of the "number of concepts."

    For me it's simply because it can be read top-down (instead of bottom-up). I despise having to visually scan down several lines for the semicolon, and scan back up to see what's being done. With all of the comments, yours is far more readable to me. Remove the comments, and his becomes much better. One grouping, one explanation.

    Ovid's would be re-written as:

    sub Readable_Ovid_Clear_MakePtag{ my $fixme = shift; # make newline-breaks into HTML paragraphs return join "\r\n", map { "<p>$_</p>" } grep { /\S/ } split "\r\n", $fixme; }

      If you've done any Lisp (or other functional style programming) you kinda get used to parsing things inside out. You almost could wrap parens around Ovid's version and . . . :)

Re: What is clear code ?
by jlongino (Parson) on Apr 29, 2002 at 03:19 UTC
    Although your code might be a bit clearer to read, as a few other posts say, the functionality is not the same. Given this code:
    my $str = "Line 1 has text, but next is an empty line:\r\n\r\nThird li +ne has text\r\n"; print "Original String:\n'$str'\n\n"; print "Ovid:\n", Ovid_Clear_MakePtag($str), "\n\n"; print "mandog:\n", MakePtag($str), "\n"; sub Ovid_Clear_MakePtag{ my $fixme = shift; # take in our parameters return join "\r\n", # join with newlines map { "<p>$_</p>" } # wrap each line in <p></p> tags grep { /\S/ } # must have at least one non-whitespace + character split "\r\n", $fixme; # break apart on the newlines } sub MakePtag{ chomp(my $fixme = shift); # take in our parameters $fixme=~s|(\r\n)|</p><p>|g; # replace all \r\n with <\p><p> $fixme = "<p>$fixme</p>"; # Add beginning and ending tags return $fixme; }
    The following results are produced:
    Original String: 'Line 1 has text, but next is an empty line: Third line has text ' Ovid: <p>Line 1 has text, but next is an empty line:</p> <p>Third line has text</p> mandog: </p>ine 1 has text, but next is an empty line:</p><p></p><p>Third line + has text

    --Jim

Re: What is clear code ?
by erikharrison (Deacon) on Apr 29, 2002 at 03:57 UTC

    There is something to keep in mind when talking about "clean" code. Code that operates within a languages strengths in usually more robust, but also more "natural". Sure, you use a regular expression, but Perl isn't really about regular expressions (entirely). Perl is more generally about list processing.

    Consider the Schwartzian Transform. This is a powerful took which is the direct product of list oriented thinking. Ovid's solution stems from Perlish thinking. map and grep are list tools, and Ovid combines them into something that is clearly in the languages idiom, and therefore "clean". An anology would be the sentence "Sarcasm is the lowest form of wit I think not".It is grammatically correct, and uses few grammatical concepts. But it is hard to read and understand because it is outside of the languages idiom.

    Cheers,
    Erik
Re: What is clear code ?
by sfink (Deacon) on Apr 29, 2002 at 22:40 UTC
    In my mind, there are two main differences between those chunks of code (ignoring the differences in functionality). First, the algorithm is different. Second, the top one chains expressions. I'll rewrite the top one without the chaining:
    sub YetAnotherMakePtag { my $fixme = shift; my @lines = split "\r\n", $fixme; my @nonblank_lines = grep { /\S/ } @lines; my @wrapped_lines = map { "<p>$_</p>" } @nonblank_lines; return join("\r\n", @wrapped_lines; }
    I would argue that this version is clearer than either original, with or without comments. (Probably the slowest, too.) While the chaining made things more confusing, the algorithm change actually made things clearer. And that's because the concepts in the new version, however many there may be, are a direct mapping to a natural conception of how to perform the task. In MakePtag(), there is an intuitive leap required to see that you can wrap delimiters around a string by replacing separators with close-delimiter open-delimiter pairs, and then wrapping the whole thing with open-close.

    I try to avoid that construct in my code. For example, I always do print "$_\n" foreach (@list) instead of print join("\n", @list), "\n" simply because the first is a more natural translation the actions I wish to perform. (It also reduces repetition of the terminator, and is much more open to modification if you want to do something a little different: print "-->$_<--\n" foreach...).

    On the other hand, for pedalogical purposes I think Ovid's is best. It answers your question, it gives a more complete solution, and it introduces a useful technique (chaining) that doesn't particularly obscure the clarity of the example because it's so easy to see the transformation I did above.

Log In?
Username:
Password:

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

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

    No recent polls found