Pruning Non-Determinacy verses Thinking Ahead.

Oh, look; now we have multiple cores inside of modern day computers. Today you can get a laptop with two processor cores in one chip for cheap, and soon Apple will be releasing a computer with 8 processor cores spread across two microprocessor chips. Noticing that the workaround being used today to allow Moore’s Law to get around physical reality is to stuff more processor cores onto a chip–which requires multithreading and multitasking to take full advantage of it–several articles have come across which attempt to illustrate the pitfalls of multithreaded programming.

Except, well, do they?

Exhibit A: The Problem with Threads, which attempts to illustrate the problem with threads by discussing the Observer Pattern:

Consider the observer pattern,5 a very simple and widely used design pattern. Figure 1 shows a Java implementation valid for a single thread. This shows two methods from a class where an invocation of the setValue() method triggers notification of the new value by calling the valueChanged() method of any objects that have been registered by a call to addListener().

The code in Figure 1 is not thread safe, however. That is, if multiple threads can call setValue() or addListener(), the listeners list could be modified while the iterator is iterating through the list, triggering an exception that will likely terminate the program.

To reiterate, because I don’t feel like copying his code across, the observer pattern example given is simple: someone calls “setValue”, and this sets the value for the object as well as tells everyone else about the value that was just set.

Then we go on for several paragraphs talking about why the code is not thread safe, to which all I can really add here is, well, no fucking shit, Sherlock, it isn’t thread safe.

Frankly, not only is it not thread safe, but the solution doesn’t even make any sense in a multi-threaded environment!

What are you trying to do here? Well, when someone comes along and changes the value, you’d like to tell everyone who cares what that value changed to. Simple enough, right? But in a multi-threaded environment, what does it mean when thread 1 changes the value when thread 2 also wants to change the value? Are the objects who want to be notified thread safe? What does it mean when a central value is changed twice by two threads? What is the semantics here?

In a multi-threaded environment, assuming the Observer Pattern should somehow be made to work overlooks a rather obvious question: what does it mean for two threads to change the same value? And the corollary: when we are notified do we just need to be told that something changed so we can refresh something–like a UI display widget–and so we just need to know the last time it changed? Or do we need to know every value transition in the order in which they occurred, because we’re driving a state machine?

In other words, by focusing upon the design model to proclaim that Threading is hard, we’ve avoided the question of what the hell it is we’re doing. And if we could answer the question “what are we trying to accomplish here,” perhaps we could then solve the problem by using an appropriate design pattern rather than trying to extend a design pattern where it doesn’t belong.

So, say instead the problem is you want to just be notified the last time something changed, so you can update a user interface element. We know that Swing runs everything within its own UI thread–so it means our setValue routine will need to use Swing method EventQueue.invokeLater() on a Runnable object which then sends out the notification to our listeners that the value has changed. Then, when the value has changed, we can determine if we’ve inserted an event into the Swing event queue and see if it has fired yet. If it hasn’t, we’re done. If it has, create and insert a new one.

The implementation is straight forward:

public class ValueHolder
{
    private List listeners = new LinkedList();
    private int value;
    private boolean fWaitToFire = false;
    
    public interface Listener 
    {
        public void valueChanged(int newValue);
    }
    
    private class FireListeners implements Runnable
    {
        private List copyOfListeners;

        FireListeners()
        {
            copyOfListeners = new LinkedList(listeners);
        }
        public void run()
        {
            fireListeners(copyOfListeners);
        }
    }
    
    public synchronized void addListener(Listener listener)
    {
        listeners.add(listener);
    }
    
    public synchronized void setValue(int newValue)
    {
        value = newValue;
        if (!fWaitToFire) {
            EventQueue.invokeLater(new FireListeners());
            fWaitToFire = true;
        }
    }
    
    private void fireListeners(List list)
    {
        int localValue;
        
        synchronized(this) {
            /* Grab value and reset wait to fire. If someone else changes me while */
            /* I'm iterating the values, that's okay; I'll just get fired again later */
            /* Since we're invoked from FireListeners internal class, we're already */
            /* in the main Swing thread, so there are no multi-threaded issues with */
            /* the list iterator here. */
            localValue = value;
            fWaitToFire = false;
        }
        
        Iterator it = list.iterator();
        while (it.hasNext()) {
            ((Listener)it.next()).valueChanged(localValue);
        }
    }
}

Notice the two principles I’ve used here: first, keep the amount of code in the synchronized block as short as possible. That way, the size of the non-syncronous section is kept to a minimum, and parallelism is maximized. Second, I’ve used a monitor flag, ‘fWaitToFire’, which is used to determine if we already have an object queued up in the Swing thread that hasn’t been fired yet. This permits me to minimize the number of times we carry out the expensive operation of creating a copy of my listener list. Since we’re only interested in knowing when the value changed, but not being notified every time the value changed, this may only notify us once if the value is changed twice, right in a row.

Suppose, however, that we need to be notified every time the value has changed, and in the order the value has changed to. Then we need to implement a thread queue: an object which doesn’t just store the current value, but a queue of all of the values that were held by this object. A thread then owned by that object runs in the background, peeling off entries in the queue and sending them out to the listener in order.

Because it’s late, I will leave the implementation of a thread queue to the reader.

There is one thing in this article I do agree with wholeheartedly:

I conjecture that most multithreaded general-purpose applications are so full of concurrency bugs that—as multicore architectures become commonplace—these bugs will begin to show up as system failures.

Absolutely.

And if the current thinking shown in the above linked article prevails–of applying inappropriate design models to a multi-threaded environment without giving a single thought as to what the original problem was–then we’re not going to find any good solutions anytime soon.

Because ultimately the goal seems to be tackling the wrong problem. The problem is not

…[adding] mechanisms [to] enrich the programmer’s toolkit for pruning nondeterminacy.

No, the goal should be to think about what the hell it is you’re trying to accomplish in the first place, and using the correct design model so as not to create non-determinacy in the first place.

On that note I’ll leave you with two thoughts. First, we have the article Thread pools and work queues, of which my outline of an alternate mechanism above for sending out every value change as it happens really is just a work queue with a thread pool size of 1 thread.

And the second is not to fear thread deadlocks–just remember the following rule: if you always lock in order and unlock in reverse order, you’ll be fine. That is, if you have three locks, numbered 1 through 3, so long as you always write your code so that lock A locks before lock B if n(A) < n(B), then you will never deadlock. That’s because deadlocks occur if thread A locks 1,2 and thread B tries to lock 2,1: thread A is waiting for 1 to come free while thread B is waiting for 2 to become free. But if you always lock in order–then you will never have code that deadlocks because you will never have the code in thread B: it locks out of order.

Sometimes that can be damned hard: it can involve rethinking how some code is written, locking locks early, for example, or even adding what seems like unnecessary thread work queues or other stuff. But if you follow the rule above you will never deadlock.

And provably correct code wins over “pruning nondeterminacy” every day of the week and twice on Sundays.

With this in mind, you can imagine the constant mental anguish that was going on inside of my head as I read the following article, submitted into evidence as Exhibit B: Barrier. I mean–deliberately trying to create non-determinacy in order to demonstrate pruning techniques? Why not just give some thought as to appropriate multi-threaded design models and techniques for proper design?

There was a time when I loved Apple’s documentation.

But since the NeXT folks showed up, Apple’s documentation has gotten remarkably worse–and in the past few years there have been no attempts to fix the problem.

Okay, here’s a question for anyone who knows Cocoa: what is the lifecycle of a NSWindow? I mean, sure, you can create a NIB representing the contents and it just “magically” appears–but who is the guy behind the curtain? How does the “magic” work? And how is it supposed to work?

There was a time when Apple’s documentation would give an introductory couple of pages about each logical unit of execution–each “toolbox manager”–which talked in some depth about how something would occur, and which routines would be called to make it happen. If there was a resource-driven initialization routine, the documentation would explain what non-resource driven routines were being invoked and how things were being wired up–so that, when we did use the resource-driven routines, there was a certain sort of “sense” to it all. We were not writing to a black box: we had a mental model of how things worked under the hood, even if some of that mental model was not completely accurate. After all, we may not have carburators anymore–but something mixes the air and vaporized fuel together to explode in the cylinder to make the engine turn over.

And my biggest obsticle to learning NeXTStep, er, ah, Cocoa, is that I don’t have the 10 years of history watching the system evolve to understand what it evolved from–as I do with the Win32 API. So I don’t have a mental model as to how it all hangs together–and Apple’s current sorry state of documentat sure the hell isn’t helping.

Some parts of the documentation do help. The Event Handling Overview sure helps. But figuring out how a Window goes from an idea to something I’m interacting with on screen–well, it’s not like the the NSWindow class overview is of any help. Two hundred plus methods, and the documentation sucks even worse than a JavaDoc dump–if that were even possible. Two hundred plus methods, and two fucking paragraphs of introductory material which state the obvious–and nothing else. Nothing on how Windows get built–nor even a mention if it is even possible to build an NSWindow without using a NIB.

*sigh*

Somehow Apple assumes from this I’m supposed to gain some sort of understanding. Yeah, right. An alphabetical dump of 200 methods with a rough grouping by “function” doesn’t exactly constitute transmitting a fundamental understanding.

Web Sites are like an Iceburg

Any web site–including e-commerce web sites–are like an iceburg: the user interface the customer interacts with it is the 10% that is above water. But 90% of the site is below water, in the form of maintanance utilities and interfaces which allow products to be uploaded, described and managed, to allow orders to be downloaded and processed and to otherwise manage the web site.

Why is it that 90% is done all on the web site as well?

I wonder why we don’t build such web sites by creating a simplified XML-RPC interface for obtaining back-end information, then creating stand-alone applications in something like Java which can process the back-end information? Yes, it adds complexity: now you need programmers proficient in XML-RPC (or whatever home-grown XML processing language you use), as well as programmers proficient in desktop development as well as in web site development.

But the upside comes from testing: once you have broken your web application into a front-end UI that is on a series of web servers and separate (and potentially multiple) back-end applications which interact with the web site database, you can test each of these separate stand-alone management programs and deploy them independent of the main web site. You can also develop them and test them separately from each other, which makes the risk of uploading updates to the production server smaller.

Further, the upside is in reducing the amount of server space you need for your web site. Since the logic of your management programs are running on the desktop and not on your servers, the overall footprint of your server has been lowered.

Of course this all assumes that you provide excellent access control via your XML-RPC interface. But you had to do that anyway, right?

And if your company does its job correctly, the hard part of developing the interface and access control tools are developed by someone smart, and specialists in Java Swing can toss the UI together in Eclipse or NetBeans. And if your XML/RPC interface is written in a simplified fashion, you can even deploy a dev server whose sole purpose is to validate requests to help developers debug things.

The Shaking Of The Voodoo Stick.

*sigh*

Why is it so much coding resembles more the shaking of a voodoo stick (that is, the random trial and error by someone who appears not to have a freakin’ clue as to what’s going on) than it does the studied fix of someone who sees a problem, studies it to find out what is going on, then fixes the problem?

Perhaps it has something to do with the fact that most developers don’t know what they’re doing, especially when it comes to someone else’s code.

Many years ago I obtained a copy of “Inside Macintosh”, the document which outlines the Macintosh development API. Except back then, it was called a “toolbox”–the term “API” hadn’t been invented yet. (Yes, I’m dating myself.) One of the most remarkable things about the original documentation–something which most modern documentation fails to emulate (and which, in my opinion is a major contributor to ‘voodoo stick shaking’)–is the design and layout of each chapter.

Each chapter of Inside Macintosh documented one “manager”, a conseptual unit of code. For example, there would be a separate chapter for the “font manager”, another for the “event manager” and so forth. While the details of the specific managers nowadays would be different–we’ve learned so much since this document was published in June of 1983–it is the idea that we can decompose a program into conseptual units and what those units are: single conseptual units we initialize, manipulate, interact with, and shut down, which is the important part.

But what was most remarkable was how each chapter was organized.

The first part of the chapter was an “About”: “About the Event Manager”, “About the Font Manager”. This would be a two to 20 page summary of why the manager was there–what it did, and why, from a high-level point of view. The chapter on QuickDraw (the Macintosh Carbon API for drawing information on the screen) was quite extensive as it gave a detailed outline of how drawing occured, and what you could draw. This summary would then be followed by a number of sections outlining some of the key concepts, such as a section on event masks or a section on font kerning.

The second part of the chapter consisted of a “Using” chapter: “Using the Event Manager”, “Using the Font Manager”, “Using Quickdraw”, which itself would be organized into “Initializing”, “Using” (with appropriate sections) and “Terminating”. Some chapters would simply describe how to do something, some would contain sample code. But in all cases they indicated the name of the function that would need to be called. So, for example, from the “Event Manager” chapter:

Before using the Event Manager, you should call the Window Manager procedure InitWindows: arts of the Event Manager rely upon the Window Manager’s data structures and will not work properly unless those structures have been properly initialized. It’s also usually a good idea to call FlushEvents(everyEvent,0), to empty the event queue of any stray events left over from before your program was started up (such as keystrokes typed to the Finder.)

As noted earlier, most application prorams are event-driven. Such programs typically have a main loop that repeatedly calls GetNextEvent to retrieve the next available event, then use a CASE statement to decide what type of event it is and take whatever action is appropriate.

And so forth.

Aside from the sheer primitivism of the actual API being discussed, what is most striking is that the discussion tells you what API functions to use and why. This clearness means that you don’t have to shake the voodoo stick: you know that in your startup code you need to call FlushEvents–and more importantly, why you should.

The third section of each chapter would then consist of the usual listing of APIs that we see in things like JavaDoc output: a list of functions grouped by the type of stuff they do–so, for example, posting and removing events are grouped together and reading the mouse routines are grouped together.

Granted, today APIs have gotten expoentially more complex: after all, its far easier to shovel code than it is to think about and write good software. But even so, there is no reason why today’s APIs couldn’t be documented using the same formula: (1) What is it? (2) How do I use it? (3) The details.

All too often documentation (especially internal documentation) fails to provide the (1) and the (2)–ephemeral properties that only live inside the mind of the developer who figured out how to do it, and often never communicated to the guy stuck using it or debugging it, and instead go for (3)–and worse, go for (3) in the context of something like JavaDoc, which is a very nicely organized list of routines with no frakking explanation as to why I should care.

And so, lost in a maze of very poor documentation–documentation which could be quite good if only we’d add a page on what it is, and five pages on how to use it–programmers today have no choice than to either reconstruct the “what” and “how” themselves through wasting countless hours digging through the code, or (if the time pressure is on) shaking the voodoo stick, slaughtering a pig, and praying to the Gods of Code that what they stuck in causes the bug to go away.

So, is C the new Assembly…

… or was it always the new Assembly?

C Is The New Assembly

This analysis is foreboding, because it’s exactly what programmers have always done when they switched to a higher level language. 10 years ago a programmer would be more likely to “switch to assembly” for a much-needed performance boost. Has it come to this? Are we moving to a higher plane? If you’re like me, you’ve probably become quite comfortable in your Objective-C universe, and somewhat dismissive of the scripting languages as they begin to encroach on our holy ground. But we run the risk of being like those losers who still insist on programming everything in assembly, while the higher-level code would be just as fast and easier to maintain.

Is C is the new assembly?

In a way, though, C was always the new assembly. When C was developed, one of the target goals of the C language was to make the assembly language generation straightforward: each statement would translate into a few machine language instructions. Further, C doesn’t require very much run-time language support: aside from setting up the BSS segment and a little code to translate the environment variables and run-time arguments into an array of string before invoking main(), C really requires no run-time language support at all.

C was always the new assembly.

One of the reasons why I love C++ was that, as originally conceived, C++ was basically C with classes. When I first learned C++, C++ only added two things to C: class support (and C++ class support followed the philosophy of C’s ‘keep it simple’), and operator overloading via function name aliasing. The beauty of C++ and the reason why I liked C++ was that you could write a C++ class and the method names and have an intuitive feel as to the assembly language that was being produced. This is very powerful when you’re working on a 16MHz 68020 processor and need to do things like refresh the drawing region of a screen in less than 20ms, which is the thresshold for most people’s ability to see a flicker on the screen. (And since application performance is directly related to algorithm efficiency and shortness of the instruction paths, having a feel for the instructions being generated helps you keep instruction paths short.)

Since then, of course, two things happened–as they always do. First, computers have gotten rediculously fast compared to that original 16MHz 68020 or the 8MHz 68000 or the 1.7MHz Z-80 I first learned to write software on. This has allowed us to the second thing: to create virtual machines and insanely long execution paths at key parts of the code (can you say ‘IDispatch’?) yet maintain the 20ms refresh rate on the screen. It’s the reason why we have 3GHz processors and need every ounce of that horsepower to do what we used to do on a computer that had more than three orders of magnitude less horsepower.

Secondly, and hand in hand with the first, we have seen the rise of computer languages which are less and less performance sensitive, but which are designed to make developers’ lives easier. Thus, we get langauges such as Java (which, even with modern JVMs and just in time compiling, is still a freakishly large pig compared to C), and C# and the .NET runtime library (which dispatches through IDispatch with shocking regularity) and the latest craze, Ruby, which proves the old adage that what is old is new again.

So is C the new Assembly? Yes, and it always was–it’s only that computers have become powerful enough that we can finally code in something other than assembly language.

Philistines!

Yesterday I cleaned out some old books in my home office and my wife took them into the library to be donated. I discovered that I had two copies of Knuth. So I brought one to work.

A co-worker (and fellow programmer) looked at the books and asked “what are those?” “Knuth,” I replied–remembering a day when I was at Caltech when that meant something. “What’s that?”

Philistine.

The Success of the iPod, the Failure of the Sony e-Reader.

It struck me why the Sony e-Reader and other similar book reader devices are doomed to failure where devices such as the iPod have succeeded, unless someone like Google comes along and solves the problem.

See, both devices have the fundamental problem of getting useable content on the device.

Now for the iPod and other music devices, getting your existing content on the device is simply a matter of dropping your CD into your computer, ripping the music, and downloading it onto the device. And this appears to be what the majority of music listeners who use the iPod have done: in Steve Jobs’s open letter he suggests only 2% of all the music on all iPods out there were purchased on iTunes–the other 98% were ripped from existing collections. Even if we assume that only 1 in 5 iPods are still in service, and thus that 2% number is artifically deflated, we still only get to 10%–meaning that at the very least, 90% of all music player content was ripped by the users themselves.

No such consumer-level ripping method exists for electronic book readers.

Now I don’t mind the idea of having to buy all of my e-book content on-line from Sony. I really don’t. I have perhaps 20 textbooks that it would be worth re-buying them in electronic form at full price if it means that I can lug all of them around on the Sony e-Reader–assuming, of course, that the books have been reformatted to work on the device and not simply shoveled to an 8×11 PDF file which simply doesn’t display well and is hard to manipulate. Because the idea here is convenience: if it worked well, it would be far more convenient than lugging around 30 pounds of books–just as it is far more convenient to lug around something smaller than a deck of cards than lugging around 250 CDs in a huge CD book in my backpack.

But I cannot do this myself. Oh, sure; I could, if I really hated myself, purchase a scanner and some optical recognition software to scan the books–but this is far more complex than dropping a CD in my Mac at home, hitting “rip”, and waiting two minutes.

And because of that, my two walls full of technical books cannot be funneled down into a small device like the full cabinets of CDs were. Instead, my two walls full of technical books are still full of technical books which I have to pluck off the shelves, while my poor e-reader sits there unused, with perhaps 10 science fiction books I downloaded from Sony using the $50 gift certificate that came with my e-Reader.

So the Sony eReader, as wonderful a piece of hardware as it is, is nearly as worthless to my regular reading needs as an old 8-track car stereo player would be playing my CDs.

Java and Application Frameworks

I’ve read in a number of developer blogs I respect why Java sucks. These comments range from how Java’s UI tools suck to comments on how irrelevant Java is to Mac development. Apple has deprecated the Java to Objective C bridge in MacOS X v10.4, and the presumption that somehow third party software won’t be allowed on the phone means that Java must not be on the iPhone.

While there are a number of very valid points, I think part of the problem I have with some of the arguments boil down to this: yes, there are serious problems with Java AWT. There are problems with Java Swing. It’s clear that the whole notion of a “look and feel manager” bites the big one–perhaps on Linux where look and feel doesn’t matter, but on MacOS X and on Windows you bloody well better look like–and work like–a MacOS X or Windows application.

But it is worth noting that creating an application in Java that looks like a MacOS X or a Windows application on those respective platforms is not impossible. In fact, it’s not really all that difficult, so long as you observe a few simple rules. It’s significantly less difficult than writing a MacOS X application in Objective C using Cocoa then porting that application to C++ on MFC for Windows.

Second, while Java has its problems, it’s not like other application frameworks (what Jens Alfke mischaracterizes as an “operating system”) are easy to use or provide a comprehensive platform in which to write applications.

Completeness and Simplicity

To better illustrate what I’m trying to get at, it’s best that we draw a graph. On the horizontal axis we show complexity from left (the API doesnt’ to very much for you) to right (the API does everything you’d want and then some). On the vertical axis we’d plot simplicity from bottom (the API is a royal pain in the ass to use) to top (creating an application can be done by a near moron). Of course it’s easy to create something simple that doesn’t do much, and it’s easy to create something complex that is impossible to use. The sweet spot is finding something easy that does everything. And while the Apple Macintosh does an incredible job of hunting for and finding that sweet spot, it’s not as cut and dry as “Cocoa rules, Java sucks!”

Of course “completeness” and “simplicity” are rather subjective–so of course you may not place things where I do. But it is useful to place them in the middle rather than grouping everyting in the far upper right and the far lower left–which is what the fanboys (both pro and anti-whatever) tend to do.

Graph of Application Frameworks

Macintosh OS

When the Macintosh first came out, there were no controls; no views or subcomponents within a window which you could create in a modular fasion like you do with CWnd (MFC) or NSView (Cocoa) or JComponent (Swing) today. Instead, you were given the entire window to draw–and it was up to your code to determine what went where.

It was this sort of primtivism that motivated me to write YAAF more than a decade ago: YAAF started essentially as a C++ framework to do exactly two things on the Macintosh. First, it provided a way to easily map from an update event in an EventRecord returned by GetNextEvent (back then we didn’t have WaitNextEvent–and we had to walk uphill both ways in the snow) into an XGWindow object representing the C++ representation of my window. Second, it provided a tree-structure of XGView objects which allowed me to break up the content area of a window into logical subcomponents which would allow me to write things like a small class representing a horizontal ruler.

On the Macintosh other more popular frameworks proliferated: PowerPlant from Metrowerks and Apple’s MacApp were two of the best known.

Today this notion of drawing the entire window as a single unit seems rather silly: just subclass CWnd or NSView or whatever, override the OnPaint or Draw or Paint routine, grab the drawing context object and draw your ruler or drafting area or whatnot. But with the original Macintosh operating system (pre System 7), you just had everything from the bottom of the title bar on down as a single, unitary blank slate–and no code support to segregate the contents into manageable units.

(One exception was the original dialog boxes, which defined a control object–but you weren’t supposed to misuse the Dialog Manager and Control Manager for general windows. And it didn’t work too well.)

Microsoft Windows

When Microsoft Windows 95 arrived on the scene it brought two things: from the Windows v3.0 world it brought the notion of a ‘window’ object hierarchy, with windows within windows. (Hense, the product name “Microsoft Windows.”) So instead of having to build one single window to draw the rulers, toolbars and controls contained by a single top level display window, you could break it into separate window objects with their own clipping regions. (In Microsoft Windows, a control (check box, radio button, etc) are all represented as custom windows in this manner.) And Windows 95 also introduced for the first time in the consumer level the notion of a flat (32-bit) address space.

This makes Win32 much easier to use than Mac OS (System 7)–though even back in the Mac OS System 6 days such things as handling color spaces and fonts were far easier than on Win32. (To date Windows still doesn’t have a decent bitblit that matches the power and functionality of Carbon’s CopyBits, and handling fonts in Windows is like pulling teeth.)

Even so, Win32 still was a pain in the ass to use. Windows were specified by custom window procedures (WinProcs) and there was no good way to store windows-specific data in a window. Further, when you really get right down to it, the right model to represent user interface elements is object-oriented programming: using individual programmatic objects to represent individual display objects. So Microsoft created MFC, which started life as a very thin wrapper around the Win32 API to map window procs and window handles into C++ objects. (Since then MFC has grown, expanded, morphed, and has been remapped several times for no better reason that I can see than Microsoft’s own “full employment for programmers” law, which means Microsoft has no less than a half-dozen different frameworks which do roughly the same thing.)

Throw into this mix NeXT, which built its own application framework–learning the lessons of Microsoft and Apple but making their own–and we arrive at today’s Macintosh verses Windows situation, where MacOS X Cocoa is definitely more complete, but perhaps only a hair easier to use. Both have automated layout tools, but Cocoa makes the mistake of flexability in message handling where a simple “chain of command” would do–while Windows is saddled with legacy APIs which are quite thoroughly broken. (For example, why should I have to map a DIB to an in-memory device context prior to performing a stretch blit–carefully keeping track of each of these objects so I don’t leak a damned thing–when all I want to do is load and draw a bitmap?)

Java

Into this mess we need to toss Java, the language that was originally advertised as The Answer–but, like the other famous answer 42, no-one really knew what the question actually was.

Java was, of course, saddled with lots of programmers who felt they were striking out new and uncovered country–and rushed in to stake their claims regardless of their qualifications to actually do the job right. While the core Java RTL (java.lang, java.util) aren’t that bad–though they’ve been refreshed quite a bit since Java v1.3–the first useable version of Java–there are many parts of Java that are poorly designed (java.io) and parts which have no business whatsoever being designed in such an awkward way. (javax.naming) Then there are things which no serious experienced Java programmer would touch with a 10 foot pole, but would rather rewrite from scratch or use a third-party library instead. (I’m looking at you, java.util.logging. I mean, what the hell?)

In the early days Sun thought of Java as the “Internet Language.” The whole idea was that we were going to have these ‘net agents’ which could crawl around the network in some unspecified way and do some really cool–but unspecified–tasks for us. The ultimate goal, so the futurists told us, was that we would somehow start up some sort of ‘agent software’ which would crawl around jumping from computer to computer searching for a way to scam tickets to the latest rock concert. (I’m serious about that!)

And into this Sun volunteered Java as the programming language those agents would be written in. (Of course Microsoft also jumped into the fray by desiging Windows to be sufficiently open enough for these ‘agents’ to jump onto the computer to do really cool things–which has opened a hole large enough to make Symantec one of the five biggest software companies in the world by selling software which attempts to close this ‘agent’ (read: virus and worm) hole.)

Of course one of the things that an agent needs to do is display simple results–and so Java AWT was born as a means for a Java application to display simple information on a web page. This ‘simple’ then grew–to eventually make it “theoretically” possible (and I use the term “theoretically” rather liberally here) to create a full-blown application. Frankly, though, no-one really cared if Java could be used to build an application–Java was all about agents scamming tickets to the next Rush concert for its programmers.

And AWT sucked. Sure, it provided more functionality than System 7: LayoutManagers, as bad as they are, are a sure sight better than having no layout managers because you’re responsible for drawing the entire content area of the window without breaking the problem down into manageable components, but frankly AWT is a royal pain in the ass to use.

Java Swing

At some point the folks at Sun figured out that their Java agents weren’t going to reach out across a 9600 baud modem and scam tickets to Oingo Boingo for their programmers, and adrift the 49ers of the Java gold rush sought out to create a new framework, Swing.

In terms of simplicity Swing is quite a bit harder to use than MFC or Cocoa. There are no layout tools, and Swing suffers the problem of handling layout by using LayoutManagers–if only because no-one has figured out how to satisfy the desparate problem of arranging controls in a dialog box which preserve the correct look and feel on MacOS X and Windows. (Linux, on the other hand, solved this problem of desparate look and feels by setting the bar so damned low that people huddle around their screens like cavemen used to huddle around fire, marveling that the soft blue glow emitted actually manages to do something functional. So while on MacOS System 7 you could be blasted out of the water by putting your buttons 16 pixels apart instead of the recommended 14 pixels, in Linux world they were happy not to have to pop up XTerm and type cryptic voodoo-invoking magic.)

But Swing is a sure sight better than Win32 for creating applications, and it is a marked improvement over AWT.

Sadly Swing is, at one level, not much better than my own YAAF framework’s original humble beginnings: it does give you the power to lay out the contents of a window without having to draw the whole thing. You do have the power to programmatically subdivide the content region into something manageable. And if you are clever enough (and aren’t afraid to crank out custom LayoutManagers like there is no tomorrow), you can put together something that does look right on a wide variety of platforms under a wide variety of font size constraints and look and feels. But for the seemingly endless list of classes and frameworks and packages, Swing provides surprisingly little functionality in a surprisingly large amount of space.

I guess Sun had it’s own “full employment for programmers” law.

Sun’s Java Swing does not provide model/view/controller base classes and it requires a little bit of head banging to figure out the magic property to get Java Swing menus up in the menu bar on the Macintosh rather than along the top of the window. (System.setProperty(“apple.laf.useScreenMenuBar”,”true”);) But it is possible.

Wrapup

Sadly all application frameworks suffer in some small part by the whole “full employement for programmers” act: they tend to have parts which are significantly over-engineered or contain layers of apparent simplicity rangling difficult to use elements, rather than the more difficult task of engineering simplicity from the ground up. Even Cocoa, which is much revered by many in the Macintosh world, has elements that are way overengineered–such as the whole “outlets/actions” model in NIBs, which give you the incredible flexability of hooking up user interface elements in ways that no sensible human being would ever want to do. (This is as opposed to the MFC’s method of passing unhandled window events to its container, which accurately reflects the logical way we think of events being handled–and which is the way Apple’s development tools rangle event actions by default.)

But then, writing user interface applications is a tough problem–even in the Macintosh world, where as soon as a user interface problem is resolved and a new tool built to solve that problem in a semi-automated way, a new and cooler user interface thing comes along (CoreVideo) which introduces newer problems.

And Swing does manage to solve the problem of how to write a cross-platform application that just works on any platform it is run on–though granted, it takes one hell of a lot of work to make it look right.

Conclusions

There are problems with Java. I’ll be the first to admit that. The only reason why I’ve specialized in as much Java code on this web site is because at work I use C++ and Win32/MFC almost exclusively–and my sample Objective C programs are just too primitive–too “hello world” to be worth posting here. And while someday I intend to repackage YAAF and my C++ efforts on Win32 and MacOS Carbon, it’s more for historic reasons, since the YAAF code is just too ancient to really be of much use. (I mean for goodness sake I started YAAF on Windows 95 and System 6!)

But it isn’t as cut and dry as “Java sux” or “Cocoa Rulz!”

Any good programmer knows to use the right tools for the job. If I’m writing code for a Z-80 microprocessor, I wouldn’t even think about looking for a Java VM–instead I’d use a mix of Z-80 assembler and C. If I’m going to write the next visually cool MacOS X application, Cocoa is the only way to go–just as if I’m going to write the next really cool WinCE app for SmartPhones, it’d be done in Win32–because .NET and MFC is just too damned heavy weight.

For cross-platform applications I’d use Java Swing–and my own mix of utilities that I’ve posted elsewhere on this site, in order to allow my Java applications to look like a MacOS X or Windows application, and not some weird reject from the lack of visual taste that is known as Linux land.