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

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.
    • Comment on Re^7: Thread on Joel on software forum : "I hate Perl programmers."
  • Replies are listed 'Best First'.
    Re^8: Thread on Joel on software forum : "I hate Perl programmers."
    by Anonymous Monk on Jun 17, 2005 at 12:41 UTC
      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.
    Re^8: Thread on Joel on software forum : "I hate Perl programmers."
    by perrin (Chancellor) on Jun 17, 2005 at 13:47 UTC
      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.

          FWIW, coming in such a long time after the party:

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

          Of course, in this particular case, the correct, optimal solution is trivial:

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

          In the more general case, I prefer another way, because it maintains symmetry:

          my @grid = map @$_, ( [ '01' .. '12' ] ) x 12;

          And to this:

          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.

          I say bingo. That’s the reason I use Perl to begin with, rather than C. (“If I had a nickel for every time I wrote for( i = 0; i &lt; LEN ; ++i ), …”)

          Makeshifts last the longest.

        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)?
          I think map and grep often lead to code that is too dense to read quickly. I do use them, when I have an operation that is short and simple enough. In particular, grep is a good "Are there any like this in the list?" operation.