Paradigm Potpourri Means Diminishing Returns

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.)

-- top

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.)

(Please address disagreements in relevant topic rather than here, after adding a topic link.)

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:

See also: MixingParadigms, NonOrthogonalLanguageFeatures

View edit of September 30, 2014 or FindPage with title or text search