Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Legible or Obfuscated?

by Velaki (Chaplain)
on Aug 10, 2004 at 10:06 UTC ( [id://381507]=perlmeditation: print w/replies, xml ) Need Help??

Legibility.

When does a piece of code become illegible? At what point do we declare it to cross the boundary into obfuscation?

There are many who would declare that a it begins with something as simple as writing

print "$_\n" for @array; # output each element in array on a separate + line
in place of
for $element (@array) { print "$element\n"; }
or even
$result = $object->method($arg1,$arg2) unless $something_else;
for
if(not $something_else) { $result = $object->method($arg1,$arg2); }

Perly English has its quirks, and most people are familiar with Merlyn's Sorting Mantra : map sort map; yet to many, nonblockified pieces of code draw some serious FUD factor. (Fear, Uncertainty, Doubt) Could it be a self-documenting code issue? Could it be that snippets, such as the above, use facets of perl fewer people understand?

How does the paradigm of Perlesque take root? What have you seen in your coding travels?

-v
"Perl. There is no substitute."

Replies are listed 'Best First'.
On Perl's "contractions"
by merlyn (Sage) on Aug 10, 2004 at 13:52 UTC
    I recently noticed that Perl is a language with "contractions".

    In English, it's much more efficient and common to say "can't" rather than "cannot" or "can not". Sure, it's redundant: you could have always used the longer form. But by permitting the contraction of "can't", you reward the more experienced English speaker with the savings of a bit of time and effort.

    Similarly, foreach $_ (...) { ... } is semantically identical to foreach (...) {...} which is semantically identical to for (...) {...}. Sure, the latter are redundant in a pure sense, but they perform the "contraction" for the experienced Perl speaker.

    So, it's best to learn the common "contractions". It saves time and typing for the expert, although it might slightly confuse a beginner. In fact, not using the contraction will likely confuse or call unduly attention for an expert, much like someone saying "can not" is when speaking English. An expert will wonder why the speaker didn't use "can't", because it sounds odd.

    When I program in other languages, I miss Perl's contractions. Having only one (or two) ways to say something leaves me without a convenient short way to do something. I'm glad I have the opportunity to write mostly in Perl.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      An expert will wonder why the speaker didn't use "can't", because it sounds odd.
      Was the choice of example conscious? Because it is wonderful. It both describes the barrier to those new to the language, and the utility to those who know the "cant".
      Right on. There's an amazing amount of natural language principles in Perl, including contractions and pronouns. I really enjoy reading Larry Wall's writing about Perl and the linguistic concepts he incorporated into the language, he has a great essay on his site about it: Natural Language Principles in Perl.

      I definitely know that I miss Perlish idioms in other languages, and I'm certain that I'm not the only one. Other languages are learning though, Java recently added a foreach loop in Java 1.5. :)

      Randal,
      Your request for an example such as "will not" vs. "wont" prompted the following thoughts...

      What about use warnings, carp, cluck, croak, and confess? This spans the reporting with more severe results starting with simple warning and ending with Die and backtrace (confess.)

      You might relate these to should, shall, shant, will not, and wont.


      SciDude
      The first dog barks... all other dogs bark at the first dog.
Re: Legible or Obfuscated?
by hardburn (Abbot) on Aug 10, 2004 at 13:01 UTC

    Paul Graham once made the point that just having each line be simple isn't everything. There is no doubt that any given line of BASIC is much simplier than almost any given line of LISP. However, on the average, the BASIC program will be much, much longer to solve the same problem. He argues that the complexity of a program is:

    effort per line * number of lines

    So if we assume that the LISP program has an average line complexity of 10, and the BASIC program is at 1, then it seems to be that BASIC is a simplier language. But if the BASIC program is 100 time longer, than it's really a win for LISP.

    He made a rather complelling argument that a paper on some advanced mathmatical topic may be so full of specific mathmatical language that it often takes the uninitiated hours to read a single paragraph. However, without that notation, the paper would be a hundred times longer than it is.

    On another point, I tend to write my code so that portions that are likely to change are easy to change. For example, lets assume that you have an AoA that needs to go into an HTML::Template loop. Here is my idiomatic solution:

    $tmpl->param( loop => [ map {{ foo => $_->[0], bar => $_->[1], baz => $_->[2], }} @AoA ] );

    The part likely to change here is the parameters being sent into the loop. As such, it's easy to change those. But look at the rest of the statement. To fully understand it, you have to realize that the first curly brace creates a block for the map statement, and the second curly creates a hashref. Plus, you need to know how to handle references in general, a concept that many new Perl programmers struggle with for a while (though IMHO, it's a critical step in learning Perl).

    Really, it all comes down to how much Perl you know. It is only unreadable if you don't know the construct used.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      map {{ PAIRS }} ...dwims the direction you said but not why you thought. If the contents of the two braces look like pairs or like statements this is used to decide whether the you just meant to introduce a block (for use with next/last/redo) or a hash. This is why map +{ }, ... is important because it looks more like a hash ref and does not involve dwimmery to decide that it is a hash. map {; ... } ... is the other dwim-free mode for running statements and returning lists (possibly of pairs).
Re: Legible or Obfuscated?
by Aristotle (Chancellor) on Aug 10, 2004 at 12:06 UTC

    As Larry says, Perl is optimized for ease of use, not ease of learning.

    Using statement modifiers is not obfuscation just because someone who has no idea of Perl will have a harder time understanding it. You shouldn't have to cater to the lowest common denominator.

    Brevity is a corollary of laziness, and makes code easier to read. If you pick your shortcuts wisely, you will reduce the amount of red tape and thus make it easier for a reader to discern what the code is truly concerned with.

    Obfuscation begins when the code uses roundabout ways of expressing its function, instead of straightforwardly stating what it is doing, so that the reader has a harder time telling the intent of a piece of code.

    Good code says exactly what it is doing, as briefly as possible, using the constructs that most closely match the way a human thinks of the algorithm.

    Makeshifts last the longest.

Re: Legible or Obfuscated?
by tilly (Archbishop) on Aug 10, 2004 at 15:39 UTC
    The answer to your question depends on the reader. There is no such thing as "maintainable code". Maintainability comes from the interaction between the code and the maintainance programmer.

    That said, there is a fundamental tradeoff that I mentioned in Re (tilly) 2: To sub or not to sub, that is the question?:

    Suppose that working with heavily factored and organized code is 5 times harder per page of code. Suppose that it does the work of 20 pages of unfactored and unorganized code. If you assume that the issue of tracking down the same bugs in unfactored code is similar to the issue of changes made for one reason affecting things all over the place, then that is a gain in productivity of a factor of 4. However whenever picking up that code I can guarantee you that you will feel that factor of 5 issue.
    That tradeoff between density and readability seems fundamental to me. It isn't fixed in stone though, good programmers look for ways to improve density while minimizing the impact on readability. (Bad programmers keep density low. Really bad programmers try to increase density but don't pay attention to readability.) The point at which you should stop trading off density and readability because of the maintainability impact depends on your audience.

    As a general rule of thumb, the more experienced the programmer that you're writing for, the more that you can expect of them. Pile things on beginners too fast, and they hit mental overload then balk. The same holds true for experts as well, but the expert has more generous limits.

    UPDATE: Fixed broken link. Thanks, hardburn.

Re: Legible or Obfuscated?
by Happy-the-monk (Canon) on Aug 10, 2004 at 11:41 UTC

    My simplistic thought-or-mantra on this is:

    Not using shortening Perl idioms makes code easier to read for non-Perl people,
    though using shortening perlish idioms introduces good Perl habits to all people...

    Cheers, Sören

Re: Legible or Obfuscated?
by ambrus (Abbot) on Aug 10, 2004 at 14:14 UTC

    Yes, normal perl code can sometimes become unreadable for those who don't use perl regularly. But isn't it the same with other programming languages?

    APL is infamously hard to read for outsiders, even more than perl. Lisp or Scheme code is reported to be difficult to read for those who're not used to it.

    Even some bash code like

    # bash functions for manipulating the path shopt -s extglob # addpath appends a directory to the path unless it is already there # eg: addpath ~/bin addpath(){ local a p=":$PATH:"; for a; do case "$p" in (*:"${a%/}"?(/):*);; (*) p="$p$a:";; esac; done; p="${p#:}"; PATH="${p%:}"; } # delpath deletes a dir from the path delpath(){ local a p=":$PATH:"; for a; do a="${a%/}"; p=${p/:"${a}"?(\/):/:}; done; p="${p#:}"; PATH="${p%:}"; } #END
    can be impossible to read (I've written this as normal code, not intentionally obfuscated), and even C++ code can get very ugly.
      Shell code of all varieties is difficult to read. With each OS having different flavors of all the same basic tools it can be really difficult to suss out (without reading reams of manual pages) what something does with all the various options. I hate shell code. Ack. Ptooey. Or .... I hate having to read other people's shell code written for their version of *NIX.
        Shell code of all varieties is difficult to read.

        Spoken like a man who has never supported SQR or read IRS instructions.

        Shell syntax has its quirks, sure. It certainly isn't as powerful as perl or as "clean" as Java or as readable as Applescript. However, for when it was written it was quite an advance. Also, it beats the heck out of DCL on VMS, which is where I first learned to really program, so maybe I look on shell programming with more fondness than others do.

        YMMV

        --
        tbone1, YAPS (Yet Another Perl Schlub)
        And remember, if he succeeds, so what.
        - Chick McGee

Re: Legible or Obfuscated?
by dfaure (Chaplain) on Aug 10, 2004 at 11:49 UTC

    The Frontier between legibility and obfuscation is thin and light as a paper sheet, moving to the slightest whisper.

    Perly English has its quirks

    As any other (almost) etnic language. Here, you'll find from raw to very polished materials, from eridite masterpieces to slang swearwords...

    ____
    HTH, Dominique
    My two favorites:
    If the only tool you have is a hammer, you will see every problem as a nail. --Abraham Maslow
    Bien faire, et le faire savoir...

Re: Legible or Obfuscated?
by perrin (Chancellor) on Aug 10, 2004 at 15:31 UTC
    Your examples are tiny enough that it may not matter, but I usually do use the version with blocks, because it translates to English more easilly.

    for $element (@array) { print "$element\n"; }
    "For each element in the array, print it with a line break."
    print "$_\n" for @array;
    "Print the current temp variable, for each element in the array."

    It's a combination of having to mentally reverse it, and the use of $_ that makes it less legible. I always use a named variable instead of $_ when I can. It's better documentation.

      I agree the example here isn't the greatest. For instance I would almost definately write that line as:

      print join("\n",@array),"\n";

      So a better example IMO would be something like:

      $count{$_}++ foreach @element;

      Which I would translate as a one liner to "increment the count for each element".

      I also think its worth mentioning the 'with' use of for:

      print $_*$_+2*$_+1 for $some->('complex')->{'lookup'}->[equation];

      which IMO translates to "print n2+2n+1 with n equaling some complex lookup equation."


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


Re: Legible or Obfuscated?
by tomhukins (Curate) on Aug 10, 2004 at 17:43 UTC

    As tilly suggests, it depends on your reader. If you're writing complex code that inexperienced programmers could never hope to understand, use complex Perl idioms.

    Programmers tend to create simpler interfaces around complex code to perform common tasks. Complexity occurs in most systems: hiding it away makes systems accessible to more people, trading off power for accessibility.

    If you like patterns, I find Christopher Alexander's intimacy gradient roughly analogous to this. Your code base has complex, private areas that few people need to interact with and simpler, public areas that interact with many more people. Your programming style can vary according to who the code is for.

Re: Legible or Obfuscated?
by ikegami (Patriarch) on Aug 10, 2004 at 15:02 UTC

    It's all about context. I tend to write a function in a fashion such that similar code looks similar. For example, if a function starts with a bunch of checks and one doesn't "look right" with a single line ... if (...);, then I use if/unless (...) { ... } for all of them.

    Another important piece of context is the importance of the piece of code. If the line is important, then I might choose if/unless (...) { ... } to make more visually impressive.

Re: Legible or Obfuscated?
by water (Deacon) on Aug 11, 2004 at 01:15 UTC
    It depends on the sophistication of the audience: who will read and maintain the code?

    Contractions and shortcuts can add clarity, but they can be over done.

    Just as with natural language, double negatives, complicated compound clauses, and large distances between the referred and the referrent -- or, as this interruption demonstrates, mid-sentence diversions, within long rambling sentences that try to do too much and thus don't do it well, compared to simpler structure -- can all serve to make a the reader of code or of prose work harder, and possibly make mistakes.

    print "foo!" unless /\S/; # too many negatives if (grep {is_important{$_}} map {mangle{$_}} $obj->method; # too compl +icated, too much span { #begin brace1 { #begin brace2 { #begin brace3 ... #begin brace-n # too much nesting! # and so forth
    water
Re: Legible or Obfuscated?
by Your Mother (Archbishop) on Aug 11, 2004 at 08:56 UTC

    Legibility is also affected by consistency. I'm doing some debugging on a code base that freely exchanges for ( i;i<@;i++ ) { }, for ( @ ) { }, blank for @, while ( i-- < @ ) { }, and foreaches. None of it is obfuscated but it's jarring to have the different cants (to build on shenme's contraction connection) thrown back and forth one after another. A single unusual style would be easier to get the mindset of and follow for debugging than all the common idioms in a soup.

Re: Legible or Obfuscated?
by Scarborough (Hermit) on Aug 11, 2004 at 14:29 UTC
    Someone back up the trail said

    "even C++ can be ugly"

    My feeling in a nutshell, if code dosn't look ugly its 100% easier to understand.

    But of course beauty is in the eye of the beholder!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (1)
As of 2024-04-25 04:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found