You could mail me or go to my home page, or the main squirrelly page.
Java has certainly become popular. It now spans over half a dozen news groups on Usenet, and multiple web sites. My purpose in writing this is to ask the question "What's so great about Java?".
The first thing I'm going to admit is that Java is very well-suited as a language for embedded applications in web pages. That's very nice, but doesn't justify all the hype. The popularity of Java can only be explained on the basis that people think it might be useful outside web applets, and I'm feeling doubtful. (To see some very nice applets, go to Gamelan and start poking around.)
Java hypers seem to talk about various advantages Java has over other languages, usually C++, and consistently discuss various ideas incorporated into Java. Almost without exception, these ideas predate Java and have not been tremendously successful. There is certainly no guarantee that throwing together several unsuccessful ideas into a new package will fail, but it isn't really a safe bet.
Java hypers also like to cite stuff that barely runs as if they were finished products. I don't trust beta software or developers' releases. In particular, I do not want to ship software that relies on it. It's one thing for a developer to work in a screwy environment, it's another to make a customer do so (despite how popular that option is). A clumsy and buggy development system is perhaps usable, but a buggy Java Virtual Machine environment is not.
So, it's April 1997. The birds are out, Java has been out for a while, and the parts of Grand Forks that aren't submerged are on fire. What's not to like about Java? Let me list the ways:
Java is portable in a way that hasn't been done much in the past. There's no particular reason to believe that this is really useful for anything besides web applets.
Portability has been achieved in several ways, over time. The typical commercial method is to compile a program several times. If a company distributes a product on CD-ROM, there's plenty of room to provide several different binaries, such as Windows 3.1, Windows 95, Macintosh 68030, and Power Macintosh. The source program will need to be altered primarily to accomodate different user interfaces and to tweak performance. The typical hacker method is to distribute source code, which may be tweaked and recompiled at will.
The Java method is to provide a base virtual machine, compile everything to that, and have the user run some sort of virtual machine emulator. This is nothing new. The idea of an UNCOL (UNiversal COmmon Language) was floated, I think, in 1961. The idea, which should sound eerily familiar, was that there should be a common intermediate-level language that compiled languages could compile to, along with interpreters or compilers to allow those intermediate-language programs to run on peoples' computers. The previous high point was the UCSD p-machine, which was used to run Pascal (and, later, C) on different systems. It was primarily intended to support Pascal compilers on machines that would not easily support one, and died when more powerful computers, easier to make compilers for, came out.
The first big disadvantage of virtual machine portability is performance, to be considered later. The second one is that it shifts responsibility to the user: it's the user's responsibility to have a good JVM available. This will become somewhat less important when the JVM becomes imbedded in operating systems, as Apple is doing with the Macintosh. Soon, a standard PowerMac will be able to run applications in PowerPC, 68030, and JVM machine code. Still, Java applications will suffer when a bad JVM is used, in ways that C++ applications will not, and programmers will be less able to do platform-specific tweaking.
Another big problem is that the entire JVM has to be implemented on whatever platform the program will run on. If a feature is not available in C on a platform, it is possible to run some C programs on it. If a platform lacks good support for multi- threading, it will be very difficult to put a JVM on it, and the rest of Java is essentially useless on that platform until threads are implemented.
The final problem is one that will not hinder Java itself, but which may cause problems for the computer field as a whole: the Java Virtual Machine is specifically designed to run Java securely. It leaves out support for function calls calculated at run time, and severely restricts data transformations. While this is clearly important in making the security restrictions work, it makes it very difficult to construct a good Common Lisp implementation. Computers based on the JVM will be limited in what they can run, and if the JVM becomes overly popular it will restrict what people can think about when designing computer languages. This is very reminiscent of what Kernighan said about Pascal, in "Why Pascal is Not My Favorite Programming Language:"
There is no escape.
This last point is perhaps the most important. The language is inadequate but circumscribed, because there is no way to escape its limitations. There are no casts to disable the type-checking when necessary. There is no way to replace the defective run-time environment with a sensible one, unless one controls the compiler that defines the ``standard procedures.'' The language is closed.
It is often claimed that Java was a development of C++, and the implication is that it should share its strengths (and, one hopes, not its weaknesses). In my opinion, there are great differences between Java and C++, and I regard Java as essentially untested although somewhat promising looking.
The chief difference is philosophy. The C++ philosophy is summed up in Bjarne Stroustrup's comment in Design and Evolution of C++:
So, if I can confidently predict misuses of RTTI, why did I design the mechanism and work for its adoption?...Every useful feature can be misused, so the question os not whether a feature can be misused (it can), or whether it will be misused (it will). The questions are whether the good uses are sufficiently critical....
while the philosophy of Java is much more restrictive. In C++, you can overload operators. This is very useful when creating new numerical classes and different sorts of pointers. It is also really easy to abuse, since now most of the operators can be made to do something really weird. Similarly, multiple inheritance in C++ is sometimes confusing, but potentially powerful. The Java approach is to remove these from the language, along with "goto", on the grounds that they're unnecessary and confusing. The C++ approach is to advise not misusing features.
Does this prevent Java programmers from writing unintelligible programs? No, there's good reason to think that no general programming language can ever accomplish that. Does this reduce the range of problems you can solve in Java? No, all general programming languages can do essentially the same things. What this does is change the expressiveness of Java. There are things you can express in C++ that cannot be directly expressed in Java, while pretty much everything in Java can be directly expressed in C++. (You can get garbage collection for C++, you can write graphics and thread libraries, you can implement interfaces as base classes with pure virtual functions.)
Now, some of us believe that the correct response to "You can write confusing programs with operator overloading!" is "So don't abuse operator overloading." Programming languages have had excessively abusable constructs for decades, and yet people have written good programs by limiting these constructs to places where they are useful. Overall, these have been the more successful programming languages. Pascal lost what looked like a tremendous grip on the programming community when C came along, because C had most of the capabilities of Pascal and a few more in addition.
Programming languages that try to limit the programmer to certain constructs run the risk of failing to include all the functionality the programmer may want. When Niklaus Wirth designed Pascal, he designed a functional language. Many large and good programs were written in Pascal. On the other hand, the faults of the language were sufficiently great to drive the marketplace to predominantly C. I don't know everything that has been left out of Java yet, and neither does anybody else. It will take years before we can be fairly sure that it contains everything we need to be productive, if then. At a minimum, we need to have several large applications delivered and become commercial successes: only then will we know that people can write effectively in Java.
Everything I've seen on the usefulness of Java is tentative. There is a Java word processor. That's neat. It's still beta. People are using it (if they are) because it's Java, not because it's a word processor. Java is obviously extremely useful for web applets; we've seen that. Any statement that it is useful for general software development is entirely speculative. Except for the JDK itself, no Java applications are achieving widespread use on their own merits. Perhaps 90% of the work has been done on some apps, but right now we don't know if the remaining 10% of the work will take the remaining 10% of the effort, or maybe the remaining 1000% of the effort.
It's obvious that Java is not suited to all programming tasks. It would be a miserable failure as a systems programming language, for example. It explicitly disallows casting data from one form to another, for example. This is in distinct contrast to languages like C, C++, and Lisp, which can demonstrably work well in all parts of a system, from implementation to applications. A language designed to work under very different requirements may not be the best suited for everything, but it is likely to be more useful in unexpected ways than a language explicitly designed for certain sorts of programming.
To nitpick further, there are several problems I see with the Java specification.
Now, if this were C++ or some other language, it would become popular before standardization, and people could fiddle with the language. By being issued as a de facto standard there's no (or very limited) chance of that happening.
Finally, as Kernighan said about Pascal, "There's no escape". If somebody finds that Java won't do what they want without ugly and difficult circumlocutions, tough.
Java language execution speed is, and always will be, bad. This is largely a result of the overspecification of the language, and partially how it is implemented.
Java is very precise in its specification of data types. Floating point numbers come in two flavors: 64-bit IEEE 754, and 32-bit IEEE 754. Integers come as 8, 16, 32, or 64-bit binary twos-complement. If a computer is not designed to support these formats, it will run slower than it ought. In contrast, most languages specify minimum precisions, and let the compiler pick out the precise form of the data. In C, you can specify a variable as "int", and it will be at least 16 bits long. With that in mind, it will be the natural size of an integer on the supporting machine, whatever that is. In Java, once specified as "int", it is a 32-bit integer. The hardware the program is run on may work best on 16 or 64 bits, and it may require special processing to run in the exact desired manner. It is likely that the exact behavior doesn't matter, and that a C-like specification would work, but that is not possible. While a compiler might manage to figure this out, there's no way to specify this in JVM code. Java was designed around the machines generally available today. The data types run well on CPUs like the Pentium or the PowerPC. In the future, it may be that 16-bit integers will become awkward, and 128-bit standard floating-point and integer types are likely to become popular. In this case, Java loses.
Another guarantee is that expressions are evaluated left to right. While C has suffered sometimes from undetermined evaluation order that is not obvious, the left-to-right guarantee eliminates some of the more useful ways the compiler can optimize code.
In short, Java was designed to be completely specified, at the explicit cost of performance. The Sun documentation of the Java Virtual Machine says so. This may or may not be important, and there are certainly advantages to complete specification. It is a tradeoff.
Java, to be ported as intended, is compiled to JVM code. This is code for a stack-based virtual machine, and is similar to intermediate code for some compilers. This is one of the forms listed in the Dragon Book, but is not the one most covered in there. It was not the one used in my compilers class either. I prefer either the syntax tree used in compilers class (which won't work as a portable binary, alas) or the infinite-register code used in the book. However, the intermediate code is the only thing that is passed to the JVM implementation, and only one class at a time.
Therefore, the JVM has to accept intermediate code of a specified format, which may not be the implementors' preference (Sun selected it because they thought it worked well on Intel processors). It won't get the whole program at once, and will typically get it, piece by piece, as the program is ready to execute. The obvious solution is to interpret the JVM code, but that's slow. The ingenious solution is to compile it fast, which speeds frequently-used code dramatically while slightly slowing seldom-used code. Since this compilation has to be fast, it can't do anything fancy. Since it doesn't get the whole program, it has to leave places to link in other classes. They therefore can be expected to produce less-than-efficient code. Further, they seem to be difficult to get right. As I write this, there are two JIT compilers for the Macintosh, one from Metrowerks and one from Apple, and neither is suitable for serious use yet.
The only way Java could be high-performance is if it were designed to be fast. It isn't. All functions are virtual, in the C++ sense, by default, and so many functions have to be called indirectly (compiler optimization can help). The lack of pointers to basic data objects means that a few C/C++ aliasing problems can be avoided, but the fact that everything else is basically a pointer prevents that from being a big win. From the performance point of view, Java is just another language, and has handicaps to boot. The only estimate I've seen is that C code is about a factor of four faster than Java for the same processing, run on a JIT compiler on Windows 95. I see no reason to think it will get much better than this.
Java has a standard graphics interface, so that code written in Java will have a roughly similar look on all platforms.
This is hardly a concept unique to Java, and has enjoyed mixed success in the past. Possibly the most successful was X-Windows, which provided a solid base for graphic programming on most Unix systems, as well as Microsoft Windows and Mac (at extra cost).
Systems that work on various combinations of X-Windows, Microsoft Windows, and the Macintosh have been around for a while, also. The C/C++ Users Journal had an article recently on C++ graphics frameworks that worked on multiple platforms (this particular article was not available on-line, sorry). I had a friend at MECC who worked on a MS Windows/Macintosh framework. This sort of thing isn't new, and isn't limited to Java.
Overall, it hasn't worked. Users are generally attached to their user interface, either because they're only familiar with one and any other looks funny, or because they've seen several and have an informed preference. It is extremely difficult to make a standard interface that automatically adapts to, say, the Macintosh, Microsoft Windows, and X-Windows with Motif, always using the forms that the user expects. Considering that different systems offer somewhat different functionality, the standard interface simply can't match the dedicated interface. The group making a MS-Windows program, or a Macintosh program, or a Motif program, will use the facilities the platform offers, and will use them in a standard manner for the platform. Any automatic translation will miss some of this.
It is possible for new interfaces to grow in popularity, although it is a daunting prospect. X became popular because it offered cross-platform graphics for Unix. The Macintosh was the first commercial personal computer with a useful graphics interface. Microsoft Windows, in its various incarnations, was pushed by a giant corporation. The Java interface will, to be successful, have to push all of these aside by the desirability of "write once, run anywhere" (currently, of course, "write once, run on Microsoft Windows and Solaris anywhere"). It's not necessarily a bad interface; consider Corel's interesting (if humungous) office software applet (which I no longer find on their site), but it is not (to me) a familiar one.
To summarize, this is an interesting idea that has had limited success in the past. Coupling it with portable object code gives it new interest, but the approach is inherently limited.
Java is not a useless language. It supports graphic constructs adequate for limited use, is reasonably easy to program in, and is, within its limits, superbly portable. It cannot match native code in performance, is demanding of the host machine, and limits certain methods of expression. In web applets, its strengths are critical and its weaknesses unimportant. In a more general context, its weaknesses will be magnified. I do not expect Java-based applications to ever be commercial successes.
All contents of these pages Copyright 1997 by David H. Thornley.