What do Scheme, Bash, and elisp have in common?
They're infinitely flexible and infinitely customizable and, if you force two users with great libraries of customizations to swap profiles, you are a cruel, cruel person.
Programming language design has a strange dogma that minimalism of features is a greater good, that distilling the smallest possible set of elegant core axioms is both possible and profitable. From there, offering this set of axioms leaves the dirty business of making workable software to blue-collar workaday programmers.
(I helped the authors of a book of interviews with programming language designers craft interview questions. Few designers of popular languages believe this fallacy. There may be a connection.)
Minimalism by itself is no vice. The minimalism which leads to insufficiency and fragmentation becomes a vice.
For example, consider perhaps the ultimate counter example of minimalism in programming language design. PHP's multiple searching functions differ in
searchtype( $needle, $haystack ) and
search_type( $haystack, $needle ) and
searchType( $neestack, $haydle ) and other permutations—and these are core language features.Similarly, the Java language's insistence that named classes are the only sufficient mechanism of abstraction leads to the use of XML data structures interpreted to generate code during startup time (as if XML were a sufficient programming language, much less a reasonable syntax for the bytecode generations and modifications necessary to emulate a sort of dynamic language) as well as the use of large IDEs to hide the generation of this XML from hapless workaday programmers.
Similarly, I have a wonderful ~/.aliases file sourced from my ~/.bashrc which contains aliases, aliases which use aliases, functions, functions which use functions and aliases, and other shortcuts I've distilled from repeated tasks. Someone can ask me "Hey, how do you perform memory leak analysis on that specific shared library?" and I can type a short command and confuse everyone because no one else understands my specific aliases.
(Alternately, I can do what a coworker does by refusing to customize my bash environment or my ~/.vimrc or ~/.screenrc and learning to get by with the default configuration on any decent free Unix-like box... but I'm far too impatient for that.)
If programming a large system is, at its heart, the distilling of the problem space to discover the proper terms to describe the business roles of the solution (and I believe that the Forth, Lisp, and Smalltalk people are right to describe it as such), then modern languages must provide appropriate mechanisms to devise, manage, and exploit vocabularies sufficient to solve business problems effectively.
Yet there's also a level beneath which the language of the solution is irrelevant, and that level is almost always "You can roll your own object system!" or "Exception handling is what you make it!" or "Iteration/recursion/
goto/call-with-current-continuation is the only true flow control mechanism" or "The hash/cons/
char * is the only true data structure!".
In other words, minimalism only works in practice when that minimum overlaps sufficiently with the necessary. Fail to provide the necessary for certain problems and you risk use-but-fragmentation or, perhaps worse, irrelevance in that problem domain.
Next time: minimalism in Perl (believe it).