Re^6: Thread on Joel on software forum : "I hate Perl programmers."
by perrin (Chancellor) on Jun 16, 2005 at 22:31 UTC
|
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. | [reply] |
|
|
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.
| [reply] |
|
|
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. | [reply] [d/l] [select] |
|
|
|
|
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. | [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
|
|
|
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?
| [reply] |
|
|
Seriously? $_ is always harder to understand than a well-named variable.
| [reply] |
|
|
|
|
|
|
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
| [reply] [d/l] [select] |
|
|
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
| [reply] |
|
|
|
|
|