I claim that piling on language features and paradigms into a language diminishes the benefits. Each additional feature will give one more options that may simplify certain aspects of the code, but because the different ways to do it grows with each feature, it is increasingly less likely that any new feature will make a significant difference.
Some may argue that diminishing returns are still returns. However, it jacks up the learning curve of both readers and writers of code. And, it complicates a language. Like a carpenter or plumber, the bigger your tool box, the more you have to lug around.
(I'm not sure that LISP counts, because it is almost a meta-language that can be used to build languages.)
If you believe (like me) that ThereAreExactlyThreeParadigms (plus a missing one), then these, being quite orthogonal, will combine to make the language far more expressively powerful at a level that's difficult to describe to someone who has only viewed them from afar. That applies to orthogonal features in general - orthogonal security, transparent persistence, orthogonal collection-manipulation, orthogonal transaction management, orthogonal process-manipulation, transparent or translucent distribution and networking of code, orthogonal exception handling, etc. - orthogonal features combine to enable much more than was possible with either feature alone. Being a good meta-language for building other languages is just another moderately useful, orthogonal, feature (called 'syntax extension')... but, like other orthogonal features, is nearly useless without the other language features.
SchemeLanguage is a good example of a language designed, from ground up, for every to be orthogonal (though vectors were later tacked on for algorithmic complexity purposes). If you take away any one feature, you lose something significant. Atop the core set of features (the 'kernel language') others are designed using a nice little (orthogonal) macro-language.
However, I'll agree that adding two non-orthogonal features isn't particularly helpful, especially when they're so closely related that they essentially solve the same problems (e.g. closures and objects). Similarly, if you already have two or three orthogonal features that can be combined to effectively simulate a third feature, it isn't useful to add that feature explicitly. As a language-designer, I'm of the opinion that a 'kernel language' should be kept as small as possible without losing anything significant to the target audience of the language, and atop that one simply adds a massive standard-library of utilities maintained in conjunction with the kernel language.
Concepts that have been accused of being unnecessary: (This is not an indictment, only a list of trials, if you will.)
- Loops (you have gotos; you can always roll your own) - I suspect somebody is being sarcastic. Nobody at c2 has proposed this. - Certainly. Someone just did. Sarcasm aside, it was a big issue not too many years ago before 'GotoConsideredHarmful' became widely accepted. - Or, more seriously, you can use TailRecursion instead...
- High level collections (anything above 'struct' and 'array': lists, maps, trees, tables, sets, relations; you can always roll your own) - Has anybody at c2 proposed this? - I've seen plenty of programmers rolling their own linked lists, designing their own strings, writing their own bignums, etc... and doing so as a matter-of-course. It doesn't help that academia teaches them to build these structures; some come away with the impression that they shouldn't use libraries, and it takes effort to pound sense into them.
- Garbage collection
- OOP (not really a targetable feature... so break it down):
- Plug together Components
- Message Dispatching - MessageDefinition
- Strong typing (at least for some domains)
- Unit tests; code checks of any sort - I suspect somebody is being sarcastic. Nobody at c2 has proposed this. - Are you kidding? A RealProgrammer writes binaries by hand, via 'cat > a.out -' then runs it immediately. ;-)
- Try/Catch blocks
- Extensible Syntax (e.g. RealMacros) - some people go so far as to say it's evil.
- Extensible Language in general (named types, procedures, functions, variables)
- HigherOrderFunctions - Allegedly can be replaced with objects, at a slight cost of verbosity
- Objects in general, because you're "reinventing tables". This argument is applied to many, many different data structures. Yes, top, I'm looking at you.
(Please address disagreements in relevant topic rather than here, after adding a topic link.)
- Sigh. So much for that suggestion. Most of these issues already have one or more topics dedicated to the cat-fights about them.
I think comments at them being necessary is because all those things are basically abstractions of a lower level concept. Garbage collection isn't really -necessary-, careful handling of malloc/free and new/delete is just fine. Garbage collection just supposedly eases it. Of course it's a situation where you have to know all of what it's doing or you get memory leaks anyway. I'm not a big supporter of abstractions where you still have to fully understand what it was trying to encapsulate to use it properly. -- LayneThomas
All you really -need- is a one-button keyboard and an excellent sense of timing. With that you can write octal or ascii (or morse) code directly in order to enter assembly instructions... or just write machine-code directly. With sufficient discipline, care, and foresight, you won't have any problems at all. Everything above that? Just supposedly eases it. Or maybe it's just Mental Masturbation. Ask top.
Garbage collection (implemented correctly) frees you from irrelevant details of memory management. High-level collections free you from onerous tasks of building and debugging them yourself for every new object, and can (or at least should) provide the majority of all collection operations you'd ever want. Closures and Functors and Objects allow you to hook together disparate, abstract parts of code without coupling them at the source-level, thereby allowing them to change independently (or even plugin) and allowing different teams to tackle and debug independently. Strong static typing and unit tests and code checks all serve a purpose in locating errors before they cause problems and simply providing or aiding ease-of-mind that changes didn't break critical functionality. Exceptions allow one to write code more clearly, with fewer distractions by excessive checks for error handling, and done right (see AbortRetryIgnore for one take) they'll improve code modularity by decreasing coupling further. DesignByContract (and use of typing to do the same) allows for easier verification of implementation in top-down design (and "everything should be built top-down, except the first time" - Alan J. Perlis, epigrams in programming). Extensible syntax (e.g. macros) and Extensible language (e.g. named functions and procedures) allow you to transform the language to an even higher level, one far more specific to the domain.
Comments from the shooting gallery:
- (Closures, Functors, and Objects:) This seems to depend on the language. I would like a specific scenario to explore this further. This is an infrequently primary claim of OOP.
- It isn't an OOP issue. Objects are just one approach towards encapsulation. Closures are another approach. You don't need both. There are dedicated topics if you wish a deeper discussion.
- I meant the "separate compilation" issue specifically.
- You seem to have made a leap that I'm unable to follow. Where does compilation get involved? I discussed source-coupling, not issues of interpretation vs. compilation. Compilation-objects (e.g. 'main.o') are almost universally at a whole different stage than any sort of object-oriented programming within the language.
- Can you point to example that demonstrates whatever it is you are talking about. "Coupling" is an overloaded and/or often-misused term. CouplingAndCohesion doesn't contain and definite evidence.
- I've thought up a fine example involving design and implementation of a rule-based trigger systems for a database, with multi-business plugins or possibly with security requirements (if you get to prickly about breaking encapsulation just to get the job done). Any particular comparisons you wish me to make? By default, I'll consider the deficiencies of using procedural, dynamic strings, or function pointers (without closure) relative to passing closures or objects. I'll try to build the example up after 26 November.
- (Strong typing, unit tests, and code checks:) But fans of dynamic or type-free languages say that heavy dependence on type management complicates programming and makes the language more verbose. [insert related topics when found]
- Fans of dynamic or type-free happen to like their code-checks to take other forms (e.g. extensive unit tests). Fans of strong typing believe it simplifies programming, allowing them to design at an abstract level (e.g. via semantically meaningful types) and make implementation secondary - if ProgrammingIsInTheMind, you can't say one group is right and the other is wrong. In the use described here, both typing and tests and various other checks over code serve a similar purpose: they help get the code correct. As far as verbosity, you mistake 'StrongTyping' for 'ManifestTyping' - please learn the difference; it's really irritating that you don't know by now.
- I know what the difference is, Mr. Rudepatronizer. It is just that in practice one usually has to specify more up front if they *rely* heavily on types. Yes, there's probably exceptions, but the generality stands.
- After having worked Haskell and OCaml, I don't believe you. And I think it unreasonable, Mr. Sophist, to make a claim and then add tons of exceptions until it's so full of holes that there was no point in making it in the first place.
- Fortunately, I'm not the only fan of type-reduced programming and languages on this wiki. Take it up on topics like BenefitsOfDynamicTyping.
- Sorry, top, but I reread that page and see nothing on the BenefitsOfDynamicTyping page supports your claim regarding 'specification up front'. I'm left still disbelieving you.
- I don't wish to debate this at this time. Perhaps another day or another type-lite fan can take over.
- (Exceptions:) This is rather non-specific. Example?
- See papers mentioned by gz in AbortRetryIgnore for decent examples. This page isn't for extended examples.
See also: MixingParadigms, NonOrthogonalLanguageFeatures