View Single Post
Old 03-26-2003, 08:29 PM   #23
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
Yui:
Sure, but what about features that are just hard to read, even when they're easy to write? I mention Perl specifically because it gets such a reputation as a write-only language. It gets this reputation because of things like its regular expression syntax (very difficult to read, and very small subtleties can change the meaning a *lot*) and the fact that a tremendously wide variety of inputs can parse to *something*.

One reason I'll call a language "clean" is if no two valid inputs in the language look very similar to each other. That is to say, if any two valid inputs in the language are reasonably easy to disambiguate from each other, especially two inputs which are basically dissimilar.
And by "disambiguate", I mean only if you're reading it. A parser, of course, won't have much trouble either way.

If you're *writing*, as opposed to reading or modifying, I agree with this statement.

Actually, Perl's remarkably fast. It's not quite up with static compiled languages like C or Pascal, and certainly not Fortran. On the other hand, it compares very favorably to anything interpreted and most things that are compiled.
That's mainly because they have a really good optimizer, though, and the fact that the whole language is designed with that in mind.
Anyway. Sorry. Off-topic.

Because good people are extremely rare. Software houses that employ a very small number of very good people will essentially never go out of business. They will also very, very rarely get really big. Most markets require a lot of customer service, and a lot of very large software to be built. Therefore, any approach that requires a very high average level of brilliance, or that allows brilliant people to be easily sabotaged by idiots they're working with, won't grow to fill the niche. It will instead be overtaken by a small army of strongly competent fellows who are, collectively, more brilliant than the five incredibly savvy guys at the other company.

That's just one of the many reasons that languages that allow good modularity are so popular.

And you're successfully making coders do that, even though no two can agree on a good coding standard, how? The only correct answer is "enforcement". The only common answer is "optimism". Where have you worked, that you haven't had problems with this? My experience with free projects is that carefully-written, carefully-posted and carefully-followed coding standards are all well and good, but free contributors simply will not follow them unless you enforce rigidly.

The same is essentially true at a professional software house, and nobody wants their job to be enforcing coding standards. Well, okay, John did, but we laid him off and he left for Norway. It's a shame, he was good at it.


Very much like that, yes. Ever notice how on modern Linux systems, root logins come configured by default to alias "rm" to "rm -i"? So instead of deleting files automatically, it'll ask to make sure you typed what you meant.

One could imagine a similar scenario where "dd" was aliased to always prompt when you used it on a hardware device (rather than just a file), so it would make you specifically say "yes" before doing something potentially stupid. The DOS "Format" command already does/did that.

I consider all of those to be basically good things. Should language designers avoid easily-abusable features in favor of features that tend to produce better code on average? Absolutely. Unquestionably. Should they remove features (like pointers) that can sabotage other people's work silently and without them specifically opting into it? Where possible, yes. Pointers specifically are a great example of a feature which can't be removed without a speed hit. I still try to use languages without them, where possible and appropriate.

Would any given lanuage be better if we added a bunch of new features? Maybe. CommonLISP plus pointers, for instance, or Java plus pointers, would be a step back. SML plus pointers would be an abomination -- like C++, it would have sabotaged its greatest asset, though for different reasons.

"Sabotaged its greatest asset?" Yeah. Being object-oriented is C++'s greatest asset. That means a real type system. The basis of data protection in a type system (private, protected, static, etc) is enforcement. Private fields aren't private as long as C++ has pointers.

Anyway. Sorry. That's a different anti-C++ tirade, and it's not like C has a real type system either -- it just doesn't pretend to.

Yui:
Thank you. This is a very concise restatement of what I said earlier about "hard to debug" and "other people's code".
Incidentally, there *are* new languages that focus on having fewer features rather than more, and some of them are very much improved by it. SCHEME is easily embeddable because of it. SML/NJ is possible because of it -- full static type analysis is essentially impossible on most imperative programming languages, and you wouldn't want it anyway. Java is cleaner because of it, having removed some nastiness that C++ added.

Sort of. You're saying here "to use closure and polymorphism, you must use a language with enough subtleties that nobody will properly understand the language". My counterexamples are Scheme, CommonLISP, Dylan and SML (for closures) and CommonLISP, Dylan, SML, LPC, SmallTalk (for polymorphism). Note that there are a decent number of languages even in the intersection of the two.

Beyond a certain number of simultaneous features, you're right, you have to have a language that's too complicated to understand. Speaking of which, if C++ has closures then we mean two very different things by "closures" or C++ has added a feature I'm not familiar with. I'm used to closures requiring lambda functions or something like them.

Actually, grunts have no established meaning and are entirely ambiguous. And complexity at the language level adds to simplicity at the algorithmic level only if you can match a language primitive with the task at hand. Near-misses on language primitives are usually as bad as not having anything at all (such as using code inheritance for physical MUD objects, as we discussed earlier, or using C++ inheritance for a system with dynamic inheritance).

For common structures (such as lists and hash tables), though, I agree -- complexity at the language level leads to simplicity at the algorithmic level. Though the stuff we were discussing earlier was all simplicity at the syntactic level, which I consider to be a separate issue.

More specifically, complexity at the standard library level tends to lead to simplicity at the algorithmic level. Complexity at the language level tends to lead to simplicity at the syntactic level.

So you feel that the potter's wheel was designed to allow more variation than shaping clay with your hands? Nope. *Less*. There are *fewer* shapes that can be manufactured with a potter's wheel, and those shapes can be created with less effort for each one. By *restricting* the expressiveness of the medium, the total labor can be reduced.
Specialization *restricts* the vocabulary of an individual, and even of a socity -- you see practically nobody that works in clay/glass hybrid objects because those are considered separate specializations so there's little overlap. That wasn't always true.

But by restricting the expressiveness of the media involved, we get everything with less labor. Old fabrics, done by hand on a loom made of strings and a rock were more complex than the most impressive stuff we can do on our big modern computer-controlled looms -- and yet our modern stuff produces it at a tiny fraction of the cost, so we're wearing simpler fabrics and not worrying about it.

By *restricting* expressiveness, we've reduced total labor.

And in the same way, the fact that I use C means I'll never have to debug a code submission that requires me to understand all the stuff that can go wrong with C++ code templates. I've saved myself a couple of months of my life that way, and I'm happy about it.

Yup. Garbage collection is argued against for the same reason -- it doesn't require you to track everything, and so it'll be overrun by higher-performance languages where you have to track all the allocations by your lonesome. The results are better, even if they're more error-prone and require more intelligent programmers.

And Perl, Python and Java overtake C and C++ while we stand in denial, because there are fifty times more people who can be perfectly adequate programmers than can be brilliant programmers, and fifty adequate guys is worth at least two brilliant guys. More on some problems. Only two? Sure. But that's still twice what the brilliant guy can do.

Of course, you could also make sure that the language the only-adequate people use is sufficiently "expressive", and then none of them can debug it. Lamentably, that's why something as awful as Visual Basic is also overtaking C and C++.

Well, except absolutes like "A and B implies A", or "not not not A implies not A", and absolutes like "this car is painted red". Which would prove your point nicely if it didn't also disprove your point.

But yes, C++ is cleaner for some specific things. The things you proved it was cleaner for were specific C++ language features (C sucks for operator overloading, I'll grant you), and ones that I feel still shouldn't be used. But in the same way that APL or Fortran absolutely rocks if you need to take the inverse transpose of the product of a 9x7 with a 7x15 matrix, C++ rocks for operator overloading.

Incidentally, APL is another long-forgotten example of a write-only language in a very specific domain. It does array processing (thus the name). It has operators for, like, everything you can do to an array. But since nobody remembers what the operators do when they read them, it doesn't matter -- the code's simply not maintainable. Rather like the way some parts of the Perl regexp system work, or some of the finer points of C++ RTTI and typecasting stuff.
angelbob is offline   Reply With Quote