The Secret History of Perl
TimToady writes "Many otherwise intelligent people seem to think that Perl just sort of happened by accident. But Linux Magazine has just now put their October issue online, and it includes an article entitled Uncultured Perl: Perl's Creator Shares his Thoughts on a Subversive Lifecycle. It's basically the secret history of how Perl infested the world, intentionally subverting everything in its path including
the NSA, Unix, and the GPL. " Reading Larry Wall stuff has to rank as one of my favorite reading experiences.
Let me see.
The localtime() documentation has been part of Perl for years. You will find it repeated in books, Perl's Y2K statement, etc. If you read the documentation rather than use the "try and guess" approach you would have known what that function returned.
As the saying goes, Assume means "Make an Ass of U and Me."
And so, after not reading Perl's documentation, not reading Y2K statements, not testing your own code (despite hearing "Y2K" being chanted for months), you do not think that the existing problem was your fault?
Furthermore if you read the documentation, those Y2K statements, etc, you will find out that the decision was made not in the design of Perl, but in the design of C. Perl chose to imitate what C did a good 10 years ago, and C chose the format for that struct over 20 years ago. Personally I think that a 4 digit year would have made more sense than year-1900. But year-1900 makes a lot more sense than a 2 digit year! (Do you like coding in windowing logic to guess the century? Me neither!)
Oh, and a pointed question. Those scripts that began returning 19100? How many of them would have returned 1900 if the year was returned as a 2 digit year like you asked? Oh really? And you have cause to complain???
Sincerely,
Ben Tilly
PS Your proposed "solution" is not even correct Perl code. I leave conclusions as to your competence to the reader.
My usual seat in the cluetrain is at A HREF="http://pub4.ezboard.com/biwethey.ht
People seem to think that they have an inalienable right to sit down in front of a program written in a language with which they are vaguely familiar and begin hacking someone else's code - and bitch when the language is not trivial enough to do that. While I am all in favor of languages with simple syntax (C, Python), or languages for morons (VB comes to mind), when I choose to code a project in Perl I don't expect some Perl newbie to maintain my code later -- because I know Perl well and I use the advanced features of the language for their power. If you don't want to take the time to learn Perl then go program in any of the zillion other languages available; but don't claim to be "just another perl hacker" or expect to be able to maintain good Perl code.
"Cause there's 40 different shades of black, so many fortresses and ways to attack, so why you complainin'?"
Hire x programmer to do x programming, and hire
y programmer to do y programming. That's your mantra? But it doesn't really make sense. Hire a good programmer is really what you want, don't you think? A good x programmer, will learn and create better y code than a bad y programmer.
The question really becomes, what languages are good programmers most likely to _want_ to program in?
First, make it work, then make it right, then make it fast, then, make it bloated!
I really do wish, however, that someone else would please write some lengthy and detailed perl apologia sometimes. Truly I do.
The first point is with respect to small changes in punctuation (not "control characters") making a large difference in semantics. This is, of course, completely true, and I saw no reason to dispute it. However, it is likewise also true in nearly every language that comes to mind, whether programming or natural.Consider the tremendous difference in choosing single or double quotes in a C string. Notice how quote choice makes a big difference in shell programming as well, and even more importantly, how this is not the same difference as C manifested! Notice how in C the presence or absence of an asterisk or an ampersand completely changes what happens, just as in Perl the presence of absence of a dollar sign or backslash (to choose corresponding construct) can have tremendous impact. Notice, too, how in C a spurious semicolon can completely change your world.
And of course, positioning of that ++ matters a lot, too.I could cite plenty of examples in English, too, such as:
- I dedicate this book to my parents, Mother Theresa and God.
- I dedicate this book to my parents, Mother Theresa, and God.
The place where Perl is particularly heavy on symbolic notation is in regular expressions. Modulo Icon, I don't know of any language or system currently in use that affords so much power. Regular expressions (ok, I know they're not truly regular by the proper language-theory definition) are an extremely compact but user-friendly interface to various sorts of FAs. Yes, of course interchanging, omitting, or deleting one single character completely changes the meaning, because each symbol carries a large amount of semantic content. This is equally true of any other language that uses regular expressions, whether it be from libc or in any other programming language. Consider how differently a circumflex can be interpreted in a call to regcomp(3) depending on whether it is the first thing in the string or not, as well as whether it's the first thing after the opening square bracket of a character class. It's subtle. You do have to be careful. Such is the nature of the beast. Then again, I haven't seen a Calculus book that eschewed symbolic notation, either, and I'm not certainly I'd care to.Let's consider the "do what I mean" effect. If you'd like another quote of mine on this matter which is also somewhat mixed in its connotation, then consider: " `Do what I mean' is really just `do what Larry means', and if you and Larry don't mean the same thing, then you may be in trouble." :-)
I guess the bottom line here is Perl's context-dependent behaviours. I have mixed feelings about this whole issue, and could probably work up a fairly substantial jeremiad in either direction. I'm talking about the fact that things like these two:
The first, being in "list context" by merit of being on the RHS of an array assignment, actually ends up being It seems pretty obvious that it's more fun to write it without that ugly split. A reasonable alternate approach would be the creation of two separately named functions to do this job. But that's not what happened.Of course, it's not as though C were free of issues of context dependence. Consider how the comma operator acts in "list context", such as when you construct an actual or formal parameter list to a function or when you create an aggregate data initialization, compared with the normal, "scalar context" comma operator. Or consider how sometimes c[] and *c are equivalent (parameter declarations), and how sometimes they are not (extern declarations). And for a real fun time, just try to explain to a neophyte why argv[0][0] is doing run-time pointer arithmetic (assuming the conventional declaration), but that data[i][j] would not be given a declaration like char data[MAX_X][MAX_Y] to create a proper two-dimensional array.
C has plenty of other "do what I mean" issues. For example:
- Letting multiplication bind more tightly than addition -- a secret, implicit rule
- Permitting but not requiring a trailing comma on aggregate data declarations
- Allowing int to be omitted in declarations involving extern, static, auto, unsigned, and volatile.
- Defaulting functions to have a return type of int.
- Assuming that for(;;) should mean while(1).
- Sign extension on some architectures.
- Freely coercing integral types
I imagine there are more of those, too, that I could come up with if I had. In fact, I'm quite sure that I could list a bunch of "do what I mean" issues for Python if necessary. Certainly the significance of whitespace and indentation is one glaring case. Another is the default nature of many libraries to raise an exception upon error, rather than returning an error status, even when that exception is, as K&P put it in Java's case, far from exceptional.So I didn't address these issues because I felt that they were largely true, but not particularly relevant. All symbolic encoding systems are subject to semantic shifts due to small changes in symbols. And many of them attempt to "do what you mean". Does Perl share these properties? Of course it does.
Finally, Jordan, you've stated that you feel that Perl lacks attributes of a programming language that lends itself to high maintainability. I don't know whether this is fair or not, because I do not know what your metric is. If you're looking for me to play the devil's advocate, I could point out things like
- minimal static analysis
- extremely late binding
- libertine autoextension of memory
- free, dynamic conversion between intrinsic types
- default mode is for fast-and-loose programming, not careful architecture with elaborate pre-declarations
However, our advocate's adversary would be quick to illustrate how easily these can be construed to be not bugs but features given the appropriate target environment. In this respect, you've probably hit the nail on the head when you mentioned trade-offs.But you haven't enumerated your criteria, so it's hard to judge what you're thinking.
Anyone can write bad code in any language. It takes good programmers to write good code. But it also takes a good language, and perl is one such language.
The problem with many languages such as LISP is that it's so _difficult_ to write good code! Perl is such a gem because it tries very hard to make your life easy. Of course, some people still do things the wrong way. It's not an issue of the language. It's a problem with the programmer.
Although I do admit that Python is an equally good language.
-Ted
Hey, Hemos & Taco, can we get Mr. Wall for a /. interview? He would be most entertaining.
+-- (Score:-1, Moderator on Power Trip)
Perl is not a rebellion against `good design'. In many senses, it is an expression of the same, where good design means something organic and adaptive, something tuned more to the wait people think than to the way computers operate. It is a kind of design which has proven itself time and again over the last several thousand -- if not in fact, billion -- years.
As for the common refrain, "I can't maintain other people's code!", this is just another bit of popular Perl FUD. Eschew such nonsense. The underlying inability may reflect on you. It may reflect on them. But it does not reflect on Perl.
What you hate is when the code to be maintained was written by an unskilled laborer, someone who doesn't understand the tenets of software design. It would be hell maintaining that code no matter what language it was written in. Another scenario for hating life is when the original coder was competent, but the person doing the maintenance is completely clueless. Here my plea:
You don't hire them for maintenance of C++ libraries, so stop hiring script kiddies (I mean nonprogrammers who can only cut and paste others' scripts) to maintain Perl. This is your fault for hiring the wrong people for the job.
I've had the pleasurable experience of maintaining a great deal of Perl code that was designed and implemented by competent, professional programmers. You cannot compare the work of the Legos kiddie with that of the professional architect. It's insulting to all three parties.
One last bit: don't denigrate the accidental programmers who've had Perl thrust upon them, or who have turned to it from a starting point of zero knowledge. They're doing the best that they can, given the circumstances, and should be encouraged, not squelched. Most programming is performed folks not trained in formal software engineering. You should compliment them for how much they were able to accomplish, not diss them for not knowing the precepts and subtleties of good design. Perl succeeds because it is available not just for professionals, but for casual programmers as well.
It's clearly documented. Always has been. You were just guessing how localtime(3) behaved instead of looking it up and reading the precise behaviour. A library API is a contract. If you sign up to using that library without reading the fine print, then you cannot complain when that fine print bites you in the ass. Stop guessing, and read!
You are incorrect in your assumption that this is somehow peculiar to Perl. Whether it's peculiar in general is another question entirely. :-) I wrote about this in a letter to Dan Gillmor. Essentially, you need to understand a struct tm. Apparently the situation is even worse in Java Script, where it appears that different implementations behave differently.
If you're on the cutting edge of Perl technology, please pay special attention to the new -DPERL_Y2KWARN configuration option. It produces an effect like this:
Interesting, eh? Another option is to use the D'oh::Year module by Michael Schwern. The author wrote about it here in Dej a News. Anyway, here's the README.Y2K file from the 5.005__63 release of Perl: We've known about this in C for about twenty years or so. So, let's not pretend you haven't been notified, ok?