Why is this Myth Still Pervasive?

chromatic on 2007-09-06T00:59:24

What I have found irritating about Perl is its TOTAL LACK OF READABILITY.... If you want proof, look at this:

my $msg = " spacey string ";
$msg =~ s/^\s+//;
$msg =~ s/\s+$//;

... I see a totally random series of symbols, as if a kid was writing something in 1337.

Perl versus Python: The eternal battle

In a government course, I put together a phone survey where the querents asked people randomly selected from the phone book their opinion on made-up issues. We invented plausible but fictional decisions of the local government and pretended that they were true.

Thanks to the Internet, I no longer have to go to that much work to find ignorant opinions from people who've done no research. Also, English is impossible to read if you don't know the definition of the word "querent" in the previous paragraph. QED.


You are an idiot

Aristotle on 2007-09-06T01:45:15

Just look at it:

msg = ' spacey string ';
msg.replace(r'^\s+', '');
msg.replace(r'\s+$', '');

That’s clearly orders of magnitude easier to read than the Perl version.

Re:You are an idiot

Aristotle on 2007-09-06T01:49:17

Oh wait, it has to be this:

msg = ' spacey string ';
msg = msg.replace(r'^\s+', '');
msg = msg.replace(r'\s+$', '');

Or possibly chain the methods.

msg = ' spacey string ';
msg = msg.replace(r'^\s+', '').replace(r'\s+$', '');

Perl can’t hold a candle to any of that.

Re:You are an idiot

pudge on 2007-09-06T02:17:34

Wow ... I've seen many complaints about lack of readability, but this has to be the dumbest one (not yours, of course, the original). Just wow.

Re:You are an idiot

pudge on 2007-09-06T02:23:30

BTW, the "blogger" is apparently only 15, acc. to his profile. After reading the rest of his post I figured he was a dumb kid. So he is.

Sometimes I worry that the chorus of "Perl, in a Nutshell" will damage Perl's reputation ("it's so easy to write, but it's not always easy to read"). Then I think, if only I could be so lucky!

Re:You are an idiot

mr.bambers on 2007-09-06T04:07:20

As a new Perl programmer, and (I will disclaim now) having never written any PHP, I'd like to point out that no computer language has intrinsic "readability". Do you remember your first time ploughing through "Learning Perl"'s 'A Stroll Through Perl'?

No programming language is readable until someone invents a programming language that reads like a native language. Think Pseudo-code, and THAT is readable (or at least you'll get the idea...) However, no-one has made a REAL language like that. Yet.

I've been told by a Perl programmer that adding comments to Perl is "not the done thing" and is (apparently) unconventional. However, if there are comments it's readable. If there are none, it's difficult to read without having a good understanding and some patience.

If I post a piece of sheet music and you can't sight-read, would you find it readable? I can read music, but it takes me 30 minutes to translate a page. I can READ it, but it's not READABLE...

(Thank you for the chance to rant with my first post... I might be more constructive next time... :~);

Re:You are an idiot

pudge on 2007-09-06T04:32:40

I agree with much of what you say, but some quibbles:

No programming language is readable until someone invents a programming language that reads like a native language.
I don't accept that: I am fluent in Perl. It is nearly as a native language to me. I'd say no programming language -- or any language -- is readable to a person until they, simply, learn that language.

I've been told by a Perl programmer that adding comments to Perl is "not the done thing" and is (apparently) unconventional. However, if there are comments it's readable. If there are none, it's difficult to read without having a good understanding and some patience.
I wonder if perhaps you misunderstood slightly. I've never heard someone say that comments are not done if they are needed; the goal, however, is to make it so that your code is self-explanatory (to someone who knows Perl, of course). If I write this:

print "Perl";
that obviously needs no comment. However, this code, that produces the same output, is much harder to read, even for a Perl programmer:

vec($str,  1, 32) = 0x5065726C;
print $str;
The latter needs comments, the former does not. And that's what many people mean when they say "don't comment": write code that doesn't need comments. Use variable and subroutine names and data structures and so on that are self-explanatory for Perl-speakers. And if it needs explanation, for you or someone else, either to know how the code works or what its purpose is, then by all means, comment!

Re:You are an idiot

chromatic on 2007-09-06T04:56:37

No programming language is readable until someone invents a programming language that reads like a native language.

I'm not sure that's even possible, at least for any interesting problems. It's not that interesting to discuss the abstract relative readability of programming languages; syntax is just one particular expression of the semantics of the solution to a problem. You have to understand the problem and the semantics of a problem as well, and once you start talking along those lines, you have to bring in the principle of the conservation of complexity.

Suddenly syntax isn't as abstract, or important. As Paul Hummer says, You simply cannot become an expert in Scheme by becoming an expert in its syntax. That's not where the power is.

You obviously have a lot to learn

btilly on 2007-09-06T12:06:58

I would suggest starting with Code Complete 2 to fill in the gaps.

After that you'll understand things like the inherent tradeoffs in commenting. It isn't as simple as "comments aren't done." And it isn't as simple as "comments make things readable." Instead it is much closer to, "comments are helpful but untrustworthy." Which is why there is a big emphasis on making your code (which can be trusted much more since errors there get noticed and fixed) read as much like comments as possible. (Much easier said than done!)

After you've come to understand principles like that, you'll be able to appreciate why pseudocode is not inherently more (or less) readable than a computer language, and making a computer language that reads like a native one does not suddenly make it easy to program. (The first language to try that approach was COBOL almost 50 years ago. There is a reason that modern computer languages are not marketed on the basis of being easy for your manager to read...) If you're lucky, you'll also be on your way to seeing how readability is an interaction between text and the reader, and how to use this to deliberately write code that is pitched to a specific type of reader.

And you'll be a better programmer. In any language you try to program in.

Re:You obviously have a lot to learn

mr.bambers on 2007-09-06T19:17:00

I do have a lot to learn, and your comments and observations about this are most welcome. I'll check out Code Complete 2 (aaah... expensing is awesome) and will soldier on with the learning.

My original comments came from the fact I do black box testing at work, and have recently started to approach the source code. One way I find comments helpful is when they describe what the following function is supposed to do. If I just read through the function (slowly... :~) and figure it out I can see what it does. I can't tell if that's what it's supposed to be doing though, and I don't usually have a programmer there to ask.

Of course, given time I hope I'll find code as readable as you all. Right now it's a barely readable black box (to me) but wish me luck and I'll be around.

And thank you btilly, chromatic and pudge for your comments and direction!

Re:You obviously have a lot to learn

btilly on 2007-09-06T21:35:15

One of my favorite comments on commenting is I find the most useful comments state what remains invariant, while the code states what gets transformed. (From this post.)

The explicit or implicit API presented by a function should not (lightly) be changed. Therefore it is often worthwhile to comment on that. And it is always worthwhile to pick a function name that tells you what it means. However the mechanics of how the function works internally should not generally be commented.

That said, there isn't any magic by which good programmers become magically able to find any code readable. You can probably improve quite a bit from where you are, but there are definite limits. For instance spaghetti is not particularly readable by anyone, and everyone gets slowed by it. Plus with any significant codebase, productivity strongly depends on how well you know your way around it. Being able to find what you want is partly a question of being able to read the code, and partly a question of being able to figure out what code to read. Memory plays a definite role in that process.

So even after you've learned to program well, you'll still have to accept that code will not always be easy for you to read.

That said, the value of good code is that good programmers can become extremely productive with it. They can understand it more easily, make changes faster, the changes are more likely to be correct, and there are fewer unexpected interactions between different parts of the code. Bad programmers also benefit from good code, but they just don't benefit as much, and their changes tend to reduce the quality of the code.

Re:You obviously have a lot to learn

chromatic on 2007-09-07T06:27:32

Plus with any significant codebase, productivity strongly depends on how well you know your way around it.

Also very important is your knowledge of the problem domain.

Re:You are an idiot

stvn_skuo on 2007-09-06T07:07:33

Perl can’t hold a candle to any of that.

But perl6 might...
http://xrl.us/ftqq
http://xrl.us/5obh

In Python that can be written as:
msg = msg.strip()

Re:You are an idiot

Aristotle on 2007-09-06T12:11:49

I expected that. Of course, until I read the documentation, I don’t actually have any idea about what strip does.

Re:You are an idiot

sigzero on 2007-09-06T18:42:24

The Python version removes spaces from both sides of the text. Just create that in a sub{} in Perl and be done with it. : )

Re:You are an idiot

Aristotle on 2007-09-06T18:56:32

I know. I’m saying that if I see msg.strip() in a random piece of Python code, and I’ve never seen the documentation of strip, then I don’t know what it does, any more than I know what the Perl code does if I’ve never read the documentation.

Re:You are an idiot

chromatic on 2007-09-06T19:54:36

You're absolutely right. I wish more people realized that.

Re:You are an idiot

ferreira on 2007-09-06T13:32:33

In Python that can be written as:
msg = msg.strip()
Hey, but that's nearly impossible to write in Perl. Let me see:

# in-place version
sub strip { s/^\s+//; s/\s+$//; }
# which would be used as
strip($msg);

Re:You are an idiot

Aristotle on 2007-09-06T14:49:30

That won’t quite work. Make it

sub strip { $_[0] =~ s/^\s+//; $_[0] =~ s/\s+$//; }

or maybe

sub strip { s/^\s+//, s/\s+$// for $_[0] }

Re:You are an idiot

sigzero on 2007-09-06T19:12:59

use strict;
use warnings;

my $string = " This is the test ";

sub trim {
        my $a = $_[0];
        $a = join(" ", split(" ", $a));
        return $a;
}

my $nstring = trim($string);

print "$string\n";
print "$nstring\n";

I don't think it takes every case...but it works with the "test" string.

Re:You are an idiot

btilly on 2007-09-06T21:43:14

The latter version can be generalized to:

sub strip { s/^\s+//, s/\s+$// for @_ }

However I don't like the idea of modifying arguments in place. Functions that do that violate my expectations. Instead I'd make a copy and return the copy. Like this:

sub strip {
    return map strip($_), @_ unless 1 == @_;

    my $x = shift;
    $x =~ s/^\s+//;
    $x =~ s/\s+$//;
    return $x;
}

Re:You are an idiot

Aristotle on 2007-09-06T21:53:00

The latter took me a while to read. I’m not used to recursion so casually… and it seems to me that deliberately creating opportunities to get the termination condition wrong is an unnecessary source of bugs.

I agree though that returning a copy is better; I wrote my code that way only because was correcting the example code.

Personally I’d write it like this:

sub strip {
    my @stripped = @_;
    s/^\s+//, s/\s+$// for @stripped;
    return @stripped;
}

On a related tangent, I’ve often wished for a variant of s/// that modifies a copy of the string and returns that.

Re:You are an idiot

btilly on 2007-09-06T22:22:43

There is a subtle but significant difference between the two versions that shows up if someone writes my $bar = strip($foo); Your code will return 1 in that case, while mine returns $foo stripped appropriately.

To fix that you would need to check wantarray. Or you could return @_[0..$#_] instead.

Personally I have a lot of utility functions that usually accept one value, but sometimes accepts a list and returns a list. I find it annoying to add the loop and the wantarray check to each one. And I find that I always am passing in only one value when I want to return one value. It is not quite as good if you're paranoid, but the assumption works for me. So for me return map function($_), @_ unless 1 == @_; has become an idiom. I just stick that in, then write the case for a single argument. At a glance I know that it will handle one argument or many, and the logic of what it does is not obscured by the mechanics of the loop.

Re:You are an idiot

Aristotle on 2007-09-06T23:30:33

I see the points, but I still don’t like the idiom. It has several moving parts that have to be arranged just so, and you have to read carefully to trace its self-interaction to understand what is really going on.

I prefer to write simpleton code. I also prefer to avoid conditionals for the same reason, so I’d use @_[0..$#_] over wantarray. All told, for a general-case idiom I’d settle on this:

sub foo {
    for ( @_ = @_ ) {
        # ...
        # mutate the iterator here
        # ...
    }
    return @_[ 0 .. $#_ ];
}

This is straight code, IMO. There is very little going on here on a conceptual level. I wouldn’t have any trouble with reading this, nor with re-deriving it on the spot. (As a fringe benefit, this structure is more efficient too – a correlation that seems frequent. But I’ll pick dumb over efficient by default in those cases where they are in antagonism.)

I don’t think the loop really gets in the way there, other than increasing the indentation level once.

Re:You are an idiot

runrig on 2007-09-07T00:07:54

I'm too dumb to remember what the difference between @_ and @_[0..$#_] is (and I'd guess others are also), so MHO is that wantarray would be preferable. I like btilly's way also, though it does make more function calls when run on a list. And on a side note, I also find the title of this thread amusing :-)

Re:You are an idiot

btilly on 2007-09-07T02:57:17

A lot of this is personal taste. All solutions are ugly. Yours involves an extra level of indentation, assignment in the for loop declaration (normally a red flag), and the subtle return construct.

I'll note that efficiency depends on your use case. My approach is more efficient for the single argument case. Yours is more efficient for the list case. (More efficient than either of our versions is to make your return depend on a call to wantarray.)

Anyways there was a period where I had to write a bunch of these. And adding one line per just worked out to be easier for me than adding several lines and adding another layer of indentation.

Re:You are an idiot

Aristotle on 2007-09-07T03:22:50

Well, I’ve actually written a module to deal with that sort of thing, so…

Eternally...

brian_d_foy on 2007-09-06T02:48:51

September. Literally even!

It does get old...

sigzero on 2007-09-06T12:13:29

There was another post about "readability" that I read this morning. I usually just post that it isn't Perl's fault that the code it hard to read it is the programmers fault/choice.

It's gone

petdance on 2007-09-06T22:48:29

His entire blog is now gone.

Here's what he originally posted:

-------

Perl vs. Python. 2 interpreted languages, whose purpose is to prevent you from writing C/C++ code. Programmers have argued for years on which is better, and many fanboys have been seen swearing at each other for no real reason. I'm here to say which is (IMHO) the better. To discover that, we must first see what those languages are meant to do for the average programmer.

C and C++ are undoubtedly the best programming languages out there in terms of speed, power, size of community, portability and usefulness. However, over the years it became clear what was the problem with them. In the many articles I have read, C++
programmers hate 2 things about their language of choice (mostly):
1)Having to write their own memory management.
2)The lack of readability.
Interpreted languages deal with both issues and that's why they're famous. It's much easier for the average programmer to write a random, not speed-requiring application with them.
Personally, I don't know C++, but I will someday for sure.

I have also read many articles conserning Perl, most writers found that it is very hard to write large applications (1000+ lines) with Perl. That's because of Perl's 'crazy' philosophy on doing things as they say. Now, I don't Perl either, but I DO have noticed its philosophy is strange. That's not the main problem for me, however.

What I have found irritating about Perl is its TOTAL LACK OF READABILITY. The winner of obfuscated C contest can surely write a more readable C program that a normal Perl programmer can write in Perl. If you want proof, look at this:


my $msg = " spacey string ";
$msg =~ s/^\s+//;
$msg =~ s/\s+$//;


Its purpose is to remove the spaces from the left and right of the string. Forgeting what the program's purpose is, forgeting even in what language it is writen in, what do you see? I see a totally random series of symbols, as if a kid was writing something in 1337. It reminds of an anonymous enterance in Obfuscated C Contest that used '-'-'-' to write zero and '/'/'/' to write one, but even that is more readable than THIS MONSTER I have before me.

I seriously think that Perl is overrated.

Next time I'm gonna check on Ruby. I have heard a lot of great stuff about it, so my expectations are high :).

Re:It's gone

chromatic on 2007-09-07T06:25:39

His entire blog is now gone.

Whoa. I took a 15 year old off of the Internet. I'm sort of proud and sort of not.

Re:It's gone

petdance on 2007-09-07T06:36:46

I posted a more welcoming comment, posting equivalent code in C and pointing out that the Perl code was much easier to read, once you understood it, and that brain cycles were better spent working on the programming problem than the specifics of how to remove spaces from a string. I invited him to look into Perl some more before writing it off.

I was hoping it might do some good.

You call that a spacey string?

bart on 2007-09-07T10:30:51

This is

"   a      spacey      string    "
It's easy to quibble about readability with trivivial examples. But a "readable" language often implies "limited in power" too. So how would you solve the same problem with the added requirement that multiple spaces should be squashed into a single space? In Perl it's easy: you just have to add the additional statement:

tr/ //s;
or

s/\s+/ /g;
(Too bad tr doesn't recognize the \s meta character class.)

So how do you tackle that in a readable language like Python? I don't know enough Python, let's stick to something I do know: PL/SQL, the (Ada-based) language Oracle includes in its databases:

function normalize_spaces(s in varchar2) return varchar2 is
  r varchar2(32000);
begin
  r := trim(s);
  while(instr(r, '  ') > 0) loop
    r := replace(r, '  ', ' ');
  end loop;
  return r;
end;
That's what "readability" buys you: a requirement for a lot of extra, very low level code. But, it least it's "readable"!

I wouldn't be too surprised that in general, Python makes you jump through the same hoops, as Guido is notorious for ripping out features out of the language he considers too advanced.

p.s. I like Javascript, and their solution really appeals to me:

function normalize_space(s) {
  return s.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' ');
}
I really like chaining in this way. Much better than the nesting of procedural function calls that you have to write backwards — the last function to call is the first one you read in the source. And Javascript knows first class regular expressions (which are like qr// objects in Perl).