in reply to Re^5: Thread on Joel on software forum : "I hate Perl programmers."
in thread Thread on Joel on software forum : "I hate Perl programmers."

Is this a serious question? A long chain of map {} grep {} sort {} stuff that shoves multiple operations on one line and uses $_ left and right is obviously harder to read than an occasional map {} here and there. I don't know if it's an official term but I sometimes call this code density.
  • Comment on Re^6: Thread on Joel on software forum : "I hate Perl programmers."

Replies are listed 'Best First'.
Re^7: Thread on Joel on software forum : "I hate Perl programmers."
by BrowserUk (Patriarch) on Jun 17, 2005 at 10:57 UTC

    It is a serious question. You would find 467617 easier to read and maintain to 467637?

    To me, the nice thing about VHL languages is that you can encapsulate a single notion into a single line. What you call "multiple operations" I see as composite parts of a single high level operation.

    When I see a Swartzian Transform, I think, "Ah! he's sorting the data". For the purposes of overview, I don't need to know how he is ordering the data, much less the mechanics of how he achives that ordering. Sorting is just a single step in the overall algorithm. Breaking that step up into several separate substeps, each with intermediate temporary storage only serves to confuse and conceal the overall algorithm.

    Once I understand the overall algorithm I may need to investigate the sort to ensure that it is being done correctly and or modify it to meet new requirements. The 3 steps of the ST are well defined:

  • Isolate the keys from the rest of the data items.
  • Compare the keys in order of precedence.
  • Retrieve the whole data items in sorted order.

    You can acheive a similar encapsulation using subroutines as exemplified by Sort::Key, but then you end up with 25+ subroutines each with a slight variations on the name. That kind of namespace explosion is my major bugbear with hierarchal libraries (and to a degree with functional languages). It requires you to memorise or look up the names, function and parameters each time you need to do something, and worse, when trying to read or maintain someone else's code.

    Better I think to have a core set of powerful, flexible polymorphic functions that can be combined in obvious way to construct the myriad variations you need. Once you understand and recognise those core constructs, you spend less time looking things up and reading what and how they work and more time understanding what the code author is (trying) to do.

    I think!


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      When I see a Swartzian Transform, I think, "Ah! he's sorting the data".
      Yeah, but it might take a few brainbeats to notice you're looking at an ST. The sort is bookended between two maps, but not any map/sort/map pipeline is an ST.

      If I see:

      @a = sort {COMPLEX EXPRESSION <=> COMPLEX EXPRESSION} @b
      it's immediately clear data is sorted. Regardless of how complex the expression is,
      @a = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, COMPLEX EX +PRESSION]} @b
      takes more time to register that data is sorted, and just sorted.

      ST's feature is speed. Not readability.

        Which is why I format the ST thus:

        @a = map { $_->[0] } sort { $a->[1] <=> $b->[1] || $a->[ 2 ] cmp $b->[ 2 ] } map { [ $_, COMPLEX EXPRESSION ] } @b;

        It makes the map / sort / map structure immediately apparent and allows for arbitrary complexity within the blocks, including multiple lines and even local variable declarations to be used without getting into that whole obfu-style thing.

        A similar layout lends itself to the GRT:

        @a = map{ substr $_, 16 } sort map { m[...(\d+)...( \d+.\d+)...([a-z]4)...] or die "Illformed data '$_' +"; pack 'A4dNA*', $3, $2, $1, $_ } @b;

        I never format single line if or else blocks one line either for same reason that doing so obscures the structure of the code.

        I also like the consistancy with map/grep/sort chains and normal assignment. That is: result = manipulation of inputs

        P6 has the pipe operators which allow you to reverse the flow src ==> tmp => dst, but I don't forsee me using that. I guess I grew up with assemblers, and even cpm/pip where dst = src was the way of things.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      It's not that I wouldn't use a ST, but I would put a big comment above it saying "Use a Schwartzian Transform to sort by...", because it's hard to recognize an ST quickly without wasting time picking it apart. Putting it in a sub would probably be even better.

      Regarding the code examples, I probably would have ended up somewhere in between. The OP used C-style for loops which would be better written as (0..12) and could have used more meaningful variables than $i and $j (like $row and $column) and used constants in place of the magic numbers 6 and 12, but it's legible. Your maps are cool, but take much longer to read than a for loop.

      For example, I would change this:

      my @nums = map { [qw/01 02 03 04 05 06 07 08 09 10 11 12/], } 1 .. 12;
      to this:
      # build the grid my @grid; my @row = qw/01 02 03 04 05 06 07 08 09 10 11 12/; for (1..$NUMBER_OF_ROWS) { push @grid, \@row; }
      No doubt this looks horrible to you, but anyone can see what it does in a quick scan. At the very least, I would change your map to a for(), since it doesn't actually use the 1..12 for anything but looping.

        Probably just an oversight in posting, but there is a problem with this:

        # build the grid my @grid; my @row = qw/01 02 03 04 05 06 07 08 09 10 11 12/; for (1..$NUMBER_OF_ROWS) { push @grid, \@row; }
        #! perlmy @grid; use strict; use Data::Dumper; use constant NUMBER_OF_ROWS => 12; my @grid; my @row = qw/01 02 03 04 05 06 07 08 09 10 11 12/; for (1..NUMBER_OF_ROWS) { push @grid, \@row; } print Dumper \@grid; __END__ $VAR1 = [ [ '01', '02','03', '04', '05', '06', '07', '08', '09', '10', + '11', '12' ], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0], $VAR1->[0] ];

        I made the same mistake initially by coding

        my @grid = ( [ '01' .. '12' ] ) x 12;

        This is being addressed in p6 by a new operator (which I cannot remember if it is 'xx' or 'xxx', but the effect is to iterate it's left operand, not replicate it. (As far as I understand it).

        It has become my "standard conversion" for where I want to type

        my @grid = ( .... ) x $n;

        but need new instances instead of replicated references to exchange the 'x' operator for map:

        my @grid = map{ ... } 1 .. 12;

        I appreciate your misgivings about the 1 .. 12, but that is (as it's position on the right-hand side tends to denote (to my brain) the lesser suboperation of the significant operation; namely that I am initialising the array grid with separate instances of some constant expression. (Oh. And there are 12 of them :).

        Beyond the thinko, the problem I have with the for/push method is that the main objective--that of initialising the array @grid--gets lost in the noise of the construction.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
        Your maps are cool, but take much longer to read than a for loop.
        <snip>
        No doubt this looks horrible to you, but anyone can see what it does in a quick scan.
        Is that really objectively true, or are you just more familiar with for and less use to map? Do you think there are any legitimate uses of map (and grep, fold, etc)?
Re^7: Thread on Joel on software forum : "I hate Perl programmers."
by BUU (Prior) on Jun 17, 2005 at 00:19 UTC
    You keep mentioning over-use of $_ as a problem but I have to confess, I don't remember any time I was particurally stumped by the usage of $_ in an expression. Do you have any examples of complicated expressions where using $_ makes them harder to understand?
      Seriously? $_ is always harder to understand than a well-named variable.
        Um. Yes?
        for( @birds ) { next unless /bar/; s/puffin/poppin/; print; }
        Versus
        for $bird (@birds) { next unless $bird =~ /bar/; $bird =~ s/puffin/poppin/; print $bird; }
        Maybe it's me or my choice of code, but I don't really see the second one as being much harder to understand.
Re^7: Thread on Joel on software forum : "I hate Perl programmers."
by Anonymous Monk on Jun 16, 2005 at 22:49 UTC
    Density is good (obfu is not, of course). What is it that mathematicians say? Something like, "One page of symbols and formula is better than 100 pages of text". Of course, a chain of a few map,grep,sort is nothing compared to J Incunabulum
      What is it that mathematicians say? Something like, "One page of symbols and formula is better than 100 pages of text"

      We may say it, but it's not always true.

      In my experience, a lot of the reason mathematics is so inaccessible to the masses is the focus on obscure notional tricks, rather than the underlying reasoning.

      It was quite a jarring experience when I finally had a mathematics teach in my final year of high school start teaching counting arguments using plain english; it all felt seemed somehow suspect, less logical somehow.

      It also demonstrated just how much time I was taught to spend translating real world problems into formal mathematical notation before I began reasoning about the solution.

      As a mathematician, I understand the power of a good notation; but I also understand how quickly formal notation can become a barrier to understanding. I was taught to always break reasoning down into discrete steps; synthesis is almost always easier than reduction. The same idea applies to coding: break code into small, discrete, provably correct steps whenever possible.

      The exact opposite of this is the mathematics trick a few undergrads pulled on their TA. Not knowing how to solve the problem correctly, they wrote the beginning, worked ahead a few stesp, wrote the desired conclusion, worked back a few steps, and linked the two sections with the words: "Trivially, the result follows", and relied on the TA to agree that the result was "trivially correct". Since their TA was a genius (with a 90%+ average in the hardest university math courses every single year), he would often agree that it was "obviously correct", and they'ld get full marks through sheer guesswork.

      Too much coding I see these days ends up being of the "trivally correct" stripe: people stare at code for three days, can't find the bug, finally decipher the flaw and fix it, and then declare what the code does to be "obviously correct now".

      Me, I learned the hard way: better a series of small steps where you can find your mistakes, than a complex expression of interwoven logic that don't quite work, though your not sure why...
      -- Ytreq Q. Uiop

        In my experience, a lot of the reason mathematics is so inaccessible to the masses is the focus on obscure notional tricks, rather than the underlying reasoning.

        I cannot express how strongly I agree with this. Of late, I've been trying hard to get into FP (several flavours) and the damndest thing is that, for the most part, I don't even understand the tutorial explainations of the basics of teh language, never mind the reference material.

        The underlying assumption that using math notation to describe functional notation on the premise that everyone will understand, is functionally flawed :) And the way functional code is typically layed out (the 2d syntax) is a total barrier to overview.

        Oh well. Just keep plugging away, maybe the pennny will drop.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.