[Yeah, 20 minutes of talking fast == wall of text. Took forever to transcribe. And still can't believe I mixed AWT, Swing and SWT in my head. That's what happens when you talk for 20 minutes with no notes.]
Initially, I learned Java in University in a course about Operating Systems. It was a little bit surprising because I was expecting, well, the Operating System being below compiled languages like C or C++, I was expecting a class teaching about Operating Systems concepts [that] it'd be using a programming language that is either, like, C or C++, which are primarily used to make Operating Systems, or something below that like assembly language. To my surprise they used Java quite effectively because they used Java to learn concepts about multi-threading and shared resources, locking and so on. I was quite surprised that Java had good enough semantics about threads, locking and shared objects that it could be used for such a "low level" concept-based class about Operating Systems.
So there's a few things that started annoying me when I started using Java. The first thing is really about memory. One of the things I really was glad to stop being limited about after moving out of Mac OS 9 to pretty much any other operating system is virtual memory. That is, in Mac OS 9 you had to pre-set how much memory each application would take (as a minimum and a maximum) before you start using it. All the other Operating Systems have virtual memory meaning that [for] every software it's as if they had "unlimited" memory (that is 4GB for 32-bit, more for 64-bit). In Java, I guess for garbage collection, they did something similar as Mac OS 9, that is you have to set your Java virtual machine with a minimum and maximum set of memory. That really annoyed me because every single time you forget to set those values it falls back to its default of 64MB, which is ridiculously small given nowadays standards of how much memory we have. So if your software is using more than 64MB then it would just crash.
Most of the other things that would annoy me with Java [are] about its API, or system libraries, the Java Runtime Environment. For example templates, or what is called in Java "generics", [were] missing until Java 5. That is before if you placed objects in a collection you had to upcast them back into [their] original classes before using them, meaning that you had lots of glue code and casting everywhere. Also for networking, the semantics for networking would be radically different than the typical "file device" pipes that you would use on UNIX environments. So instead of being all based around file in [and] file out descriptors, they used their own semantics. Only in Java 4 they started having this additional API called NIO ("New I/O") that would reproduce the UNIX file-based networking concepts into Java, and initially that was quite buggy.
There's a few other things that kind of shocked me, but I was lucky because I started using Java with Java 1.4. It's the graphical user interface libraries. Initially it was AWT, and of course that's woefully inadequate. It's was too low-level and there's almost no facilities or widgets that you could use out of it ["out of the box"]. So eventually they made "Swing Widget Toolkit" [not SWT], which in terms of API is catastrophic. They tried to make it Object-Oriented, but they did it in an awfully bad way. So you end up having to use IDEs that generate a ton of code for you that would glue all the pieces (all the widgets) together. I was expecting Java to adopt some of the new practices of using markup, that is a description language or file like XML or text, that would describe: "this is my interface, and those are the functions or properties I'll hook into to get or set information from this interface". Basically what Netscape did at the end of Netscape [Navigator] and Firefox, and [so] why you have so many plug-ins in Firefox. But instead of doing that, it's like, yeah, "write a ton of code and glue everything together manually". It may be Object-Oriented, but the "Object-Orientedness" had no effect whatsoever to make you job easier.
And of course there's the [SWT], the widget toolkit from IBM, that was back then supposedly faster because it hooks directly into the widget engine of your Operating System. You had more features, it would look more native to your Operating System environment, but it's not cross-platform. It's a DLL file, so you have to recompile and adapt it for every single Operating System out there, and of course it's supported mostly on Windows, and little bit of Linux, and they kind of forget about Mac. Completely defeating the purpose of "cross-platformness". And also the Mac version was, and still remains, shitty and buggy that every time I want to run some [SWT] it kind of crashes, it's slow, it integrates even less than the Apple support of Java on the Mac using [Swing]. It's really bad, I try to avoid it all the time, which reminds me that IBM, it's not a very good company in terms of respecting anything other than their own mainframes and environments.
One of the reasons why I still consider Java my main programming language is because the coolest thing about Java is its virtual machine. The environment of the virtual machine and its capabilities are well above and beyond most if not all other programming and scripting languages you get out there. The reason being that the virtual machine has a truly reduced instruction set, because it was fine-tuned for the Java programming language first. But what made that interesting is that, well, indirectly Sun, with Java 1.2 (if I remember correctly), they introduced introspection. That is, at runtime you could look at some Java object and figure out and what is its class, what are the capabilities of the class, what are the methods of the class, and so on and so forth. That is, discovering the attributes of an object at runtime rather than at compile time. So instead of depending on compile-time semantics in the Java programming language to cast stuff and figure out what's the interface and so on and so forth, you'd just look at an object and figure it out. This led to "Java Beans" which lead to the concept that most of what we take for granted for Object-Oriented Design, that is you make base classes, interfaces, derived classes, and you design all around that, which is static, compile-time design, you'd depend on dynamism of the objects and you depend on basically programming by convention. Which is the whole point of Java Beans, that is if you have a bunch of functions called "get" or "set" then you can infer just from the name of the functions which are "properties" of the object and start interacting with that object without having known or seen that or compiled with or linked with that interface in the first place.
This is really cool but what made it even better, and the reason I was talking about the instruction set of the Java virtual machine is because once you have that, then it's pretty easy in Java to generate bytecode and load that at runtime. Meaning that you have stuff that's nearly impossible to do in another language, like an "Aspect-Oriented" programming intercepting and using "aspects" on object at runtime based on function signatures, class names, stuff like that. And to be able to do that you need to be able to compile at runtime a new class that would be the interceptor class based on the signature you discovered at runtime. This is something that, normally, on a PC, having self-modifying code is usually identified as a virus, but in Java it actually opens doors to not having to worry about integration at compile-time, but just pushing that as much as possible at runtime. Again I was saying it opens doors for runtime Aspect-Oriented programming, it opens doors to really interesting cases, not only running remote objects which was introduced with J2EE, but also sharing objects, that is having objects that look like they're part of your virtual machine but actually they are stored elsewhere. Terracotta is an incredible library for that, where you could have several virtual machines sharing at runtime exactly the same objects. But locally in the virtual machine the objects would be generated, the bytecode would be generated at runtime to look like the remote object. And when you interact with it, it feels like you're using the original object, in reality all the operations are intercepted and then sent as remote operations to the real object, and because of the strong locking mechanism in Java then the object is shared amongst multiple virtual machines as if the virtual machines were just different threads in a single virtual machine.
The instruction set is also something that helped the development of multiple scripting languages on top of the Java virtual machine. There's Groovy, there's of course the Java version of JavaScript, there's Python (called Jython in the Java version), there are many, many, many of them. Even though the instruction set was really tailored towards Object-Oriented design and the Java programming language, you gain all the advantages of the Java virtual machine. And so it really becomes like a "thin layer" between the actual scripting language on top and the physical machine below. It frustrates me to see so many projects that develop scripting languages like Perl, and whatever happens with Perl 6, Python, shell scripts, you name it, that have a tendency to define their own virtual machine just for the sake of compiling a scripting language into that virtual machine and then running it. Well, you already have the Java virtual machine, so you could just use that. If the script is compiled at runtime or statically before it's being run, it doesn't make any difference for the user, so it means that in the end what you're running is pretty much the same thing as you would run like real Java code. So all the Enterprise-y features you'd get with Java, including Terracotta, Aspect-Oriented programming, you name it, are applicable to any scripting language using the Java virtual machine.
Given its performance, it's one of the best virtual machines out there. There's still on caveat in terms of its performance, and it's a recurring reason why people "don't like Java", or say "Java is slow", is its memory speed. I/O, basically. Java is slow with memory because it's made to use objects in memory and has a very high-level abstraction for accessing those objects. It pretty much means that if your code was really made to or oriented towards having an array in memory and just changing numbers, memory operations in general, generating and deleting millions of objects per second, that's where it really pushed the limits of the garbage collector. Now in Java 6 the garbage collector pretty much kicks ass. But up until then the garbage collector was not necessarily that good, and you have to remember, every time you add a layer on top of whatever memory I/O system your computer has you're going to get additional delays. And memory I/O is the most important bottleneck right now in computing. Laptops' I/O haven't gotten much better in the past few years, memory is not that much faster, actually the entire computing environment is slowing down because I/O is still crap. Memory access is still crap. Reading from the hard drive is still crap. So you have a very small Java program that the use wants to launch on their Windows desktop. Well, you have all the Java libraries that need to be loaded into memory, and then it has to create and the garbage collect thousands upon thousands of objects per second, and you're running that on a really cheap laptop with too slow memory and a hugely bottlenecked motherboard. The result? It's going to be slow. And there's not much that can be done.
Well, there [are] some things that were done for running Java of cellphones, which is surprising. If you can run software of cellphones using Java, then maybe Java is not that slow, but that's because those software developers would be kind of slightly insane, I guess, but they also know that the bottleneck, especially on cellphones, is memory I/O, and they would pre-allocate those objects and recycle those objects all the time. That's why you have some libraries like Javolution that are really interesting when your bottleneck becomes I/O in memory. So if developers know that the bottleneck is memory then how come they [not] careful about how they create new objects and delete them, especially with String manipulation, image manipulation, anything that's memory intensive? That's what frustrates me that the only time outside of crappy old cellphones that Java is used in a consumer device, Blu-Ray, they used it for totally the wrong reason. It was supposed to be used for interaction and visual stuff and interactive menus and games and whatever, but the way they use it now in Blu-Ray is to basically decrypt the Blu-Ray disk before being played, to prevent piracy, which of course totally failed, but that's not the point. When they developed those CPUs in those Blu-Ray players they developed the minimum amount of memory bottleneck and CPU possible to make it run for the specifications of multimedia use. And the net effect is that you have to wait a few minutes before playing any Blu-Ray disk. It feels like we haven't learned anything about the memory I/O limitations of Java and we just use that worst possible way that is decoding gigs upon gigs of encrypted data off a Blu-Ray disk on an vastly under-powered CPU that's not supposed to be used for that anyway.
But otherwise, in terms of software design and architecture, it is the most advanced programming environment (I say that because it's the language and virtual machine) you could find anywhere. Yes, there's bloat, yes, there's market needs so that there's lots of books about it and there's lots of stupid Java developers writing code in Java thay shouldn't write, but if you know what you're doing then this is a surprisingly versatile environment, because of the virtual machine, because you can do code polymorphism at runtime, which is unthinkable in any other environment, because you can do pretty wild stuff in terms of integration, in terms of coupling objects, in terms of new ideas and concepts that you could build on top of the virtual machine that don't depend on the Java programming language at all. I mean, if you don't like the Java programming language, then who cares, you could build your own. And that's what I pretty much see Java as a language that will still exist in 20, 30 years. It's a milestone because of its great engineering of the virtual machine, and regardless of its bad market position, regardless of how it was badly used by pretty much everybody, its initial marketing with Java "applets" was ridiculous, cellphones was ridiculous, the virtual machine will stay. And the environment is just incredible. And now it's GPL, it's open source. So, I'm not afraid of investing so much energy and time into developing into Java, because it's going to stay. And it is one of the most advanced environment out there. And regardless of what's the current trend right now, of what's hot or not, mind you in 20 years time it's still going to run really fine, and it's something you can build on.
Published on November 14, 2009 at 10:33 EST
Older post: APJ 5: Java
Newer post: APJ 6: The Future