by Conrad Weisert
October 12, 2012
© 2012 Information Disciplines, Inc.
Thirty years ago programming-language experts were debating the merits of large languages such as PL/I, Ada, and Algol68 versus newer small languages like BASIC and C. The small-language advocates pointed out the ease of getting started in a language one could learn in an afternoon, and disparaged the larger languages as "bloated", "arcane", and "error prone". The large-language advocates responded by pointing out the greater "power", "flexibility", and "elegance" of their favorite tools.
Each side produced examples which clearly showed the superiority of one of the languages in terms of ease of coding and testing, understandability, and ease of change. I participated in some of the debates and wrote a few papers in support of the large-language faction.
Eventually it appeared that the small-language faction was winning, partly because of the emergence of small desktop computers. C and BASIC along with a few experimental small languages became the popular fad tools for modern applications. The programming world lost interest in PL/I and Algol68, which, despite their superior power, started to fade away for lack of new users.
Object-oriented facilities built as C extensions, Objective C and later C++, added some complexity but retained the small-language style of C.
But then the small languages evolved. They grew, version by version, release by release, into truly mammoth languages, far bigger and more complicated today than any of the earlier disparaged large languages!
When Java appeared, it was greeted as an even smaller language than C++. It combined object-oriented flexibility with even greater simplicity. Advocates claimed (and still do) that one could develop a Java program in one fourth the time required to develop the same program in C++, and the program would have fewer residual bugs. If you want to learn about Java 5 today, you can get a copy of this book:
|David Flanagan: Java in a Nutshell, 5th edition, 2005, O'Reilly, ISBN 978-0-596-00773-7|
Mr. Flanagan's "nutshell" consumes 1224 pages! His explanations are sometimes so terse, that you'll want one or more additional texts, including this highly respected one:
|Joshua Bloch: Effective Java, 2nd edition, 2008, Addison-Wesley, ISBN 978-0-321-35668-0|
The reader can't help wondering what the earlier Java enthusiasts who proclaimed the language's "simplicity" and ease of learning would make of some of Bloch's advice, such as:
Because the strategy interface serves as a type for all of its concrete
strategy instances, a concrete strategy class needn't be made public to export a
concrete strategy. Instead a "host class" can export a public static
field (or static factory method) whose type is the strategy interface, and
the concrete strategy class can be a private nested class of the host.— p. 105
Each instance of a nonstatic member class is implicitly associated with an enclosing instance of its containing class. Within instance methods of a nonstatic member class, you can invoke methods on the enclosing instance or obtain a reference to the including instance using the qualified this construct. — p. 106
The serializable proxy pattern is reasonably straightforward. First, design a private
static nested class of the serializable class that concisely represents the logical
state of an instance of the enclosing class. This nested class, known as the
serialization proxy, should have a single constructor, whose parameter type
is the enclosing class. This constructor merely copies the data from its argument:
it need not do any consistency checking or defensive copying. By design, the default
serialized form of the serialization proxy is the perfect serialized form of the
enclosing class. Both the enclosing class and its serialization proxy must be
declared to implement |
Actually those explanations make perfectly good sense in context, but we still wonder how they illustrate the small, simple language one can learn in an afternoon. Ask your programming staff to read those pages and summarize them for you.
Surprisingly, we find not only that Java and other originally small languages have grown to massive size, but also that they've brought their supporters along with them. The very same programming communities that once vigorously argued for small programming languages now enthusiastically embrace and use today's monsters! Incremental growth has made something acceptable that would have horrified the same programmers or their predecssors in 1985.
"Hold on," a Java partisan will exclaim. "That's not a fair comparison. Most of the content of those books is concerned not with the Java language itself, but with add-on libraries. The Java language is still small and simple. All those library classes just provide a rich collection of reusable modules which a programmer is free to draw upon or ignore."
"Fine," I'll reply. "When you advertise for an experienced senior
programmer fluent in Java would you bother interviewing a candidate who claimed
mastery of the core Java language but admitted unfamiliarity with, say, the collections
library or the
From the start Java (as well as C++ and C#) has been confusing us about a meaningless distinction between the language and its standard libraries. What most programming experts and managers consider to be Java is:
That's a lot more than the the core language.
The Java situtation is made worse by all the leftovers. Reflecting incremental contributions and symptomatic fixes, Java with its libraries is loaded with multiple facilities providing duplicate or overlapping functions with incompatible or inconsistent interfaces. Some of those facilities have been "deprecated", but remain available. If we had seen David Flanagan's 1224 pages in 1990, we would have advised Sun to throw away that whole out-of-control mess and start over from scratch. Of course, the millions of programs and thousands of programmers committed to Java today render that solution impossible.
One of the design goals of PL/I in 1964 was clean subsetability. A programmer could learn and use a simple subset of the language without risking surprising interaction with unfamiliar parts of the language. A useful subset of PL/I could indeed be learned in an afternoon.
That's not so easy in Java. A neophyte casual programmer who has no use for or interest in the object paradigm still has to code a class definition to contain a main program, which in turn must declare unnecessary command-line parameters in a fixed form. To obtain numeric keyboard input the program must either instantiate a Scanner object or invoke clumsy conversion functions.
In addition to beginners, more serious programmers are also easily confused. In my advanced Java courses I may begin by asking the students the purpose of that main class and the purposes of classes in general. Many of them, having completed an introductory course, have no idea, nor can they explain the function of or need for various import statements that they automatically insert in every program they write. What many beginning students seize upon is emulating a pattern of code that appears to work in examples they see in in their textbook or the instructor's presentation. If it works, fine; if it doesn't, they flail by trial-and-error until they hit upon something that does.
We've picked on Java because its partisans make the stongest outdated claims for its simplicity, ease of programming, and reliability, and because it has evolved into the worst mess of all. But the same arguments apply, to a lesser degree, to C++, C#, and Microsoft's massive Visual Basic. Small programming languages still exist, mainly in specialized areas such as scripting languages, but the "mainsteam" languages will never again claim smalless or simplicity as a virtue.
Return to Technical articles
IDI home page
Last modified November 1, 2012