I am in the camp that says keep the abstraction level somewhere in the middle, not too low (painful) and not too high (you will lose a lot of people). There is a happy Buddhist middle there somewhere.<p>Almost any code meant to be used by other people (i.e not throw-away scripts, but even some of those!), even code written by almighty Lispers, will need to be tweaked by another person at some point - they call that "maintenance" but since that term comes with baggage, I say tweaking.<p>Great Lisp (and by extension any very-high-level-abstraction) tends to emphasize the elegant proof aspect of it, or the poetry aspect of it, depending on whether you come from the math or the art bent of mind, which, of course, need not be mutually exclusive. "Painters and Hackers" captures this.<p>But refining code this way can leave out later day tweakers in a state of dread. This is why really great math profs don't just recite the super-elegant proof but actually "motivate" it, with examples, with analogies and so on, none of which will be found in the proof itself.<p>A medium-level abstraction language will tend to leave in the analogies and examples, in a sense, so the tweaker will find some guide-posts. At the very least, he can turn a little knob here and there, and there is a bit of continuity in his experimentation. With dense, super-abstract code, a single token can hold the hold galaxy but will take arbitrarily long to figure out.<p>Sorry for the long, rambling comment, but my personal experience (I have shipped a lot of stuff) is Buddha is right. We must avoid extremes and go for the middle.
"What static type systems force you to do is talk about the data flow of your code. This isn’t so that humans can understand it (though with some discipline it’s possible to create readable code this way), but so that the compiler and runtime don’t have to figure out what the data flow will be when your code is executed. It’s really a form of optimization."<p>I've been thinking along similar lines recently, and I was pleased to see this put so succinctly. If static typing is merely optimization, it follows from Knuth's Law that the first draft of your program shouldn't be statically typed. The ideal high-performance language, then, is one in which it is easy to write dynamically typed code, but also one that lets you selectively type your program where necessary, without a lot of changes. I haven't seen too many languages that do this, though; I believe Lisp allows it, as do VB, Boo, and Actionscript 3.0.
Instead of worrying about K&R, memory pointer mismanagement/code that can't compile/code that core dumps, Java* lets you screw up on higher-level issues (class design, coupling, coherence, anti-patterns)<p>* (and other languages that usually don't allow programmers to manipulate memory directly)
What about all those complex APIs and exceptions? NullPointerException still makes you somewhat uncomfortable (if not as much as seg-fault). I guess there's no "perfect" programming language, all have their own virtues and vices.