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.

Style Guides

A question came up at work: I had rewritten a bunch of code and the fellow I’m working with was unfamiliar with my programming style guide. (Why are all your structure fields starting with lower-case ‘f’? And why do globals start with ‘g’?) His programming style came from the Windows Hungarian Notation world, so it’s not like this was a really dumb question. (Why are all of your fields named like their floating point numbers?)

But I cut my eye-teeth on C++ way back in 1990–and the programming style I adopted way back then came from Apple’s unofficial C++ style guide.

After 17 years bad habits are hard to break. :-)

Mail Server Uploaded

Several years ago I needed an MTA to run on an old MacOS X box that was running the Chaos In Motion web site, as well as the PandaWave web site. So I rolled my own. Didn’t need anything complicated; just something that could be scripted via XML and was running maybe a half-dozen different incoming e-mail locations.

So I rolled my own. I first rolled a library which could handle the SMTP and POP3 protocols, then an implementation that extended the library to store incoming and outgoing messages in various directory locations on the server box.

Years later, and I don’t have the time to productize this. Further, most MTAs seem to be moving towards being free and open source–so I may as well upload it under the BSD license in case someone out there finds it useful.

Which I did.

The library that implements the POP3 and SMTP protocol and parses incoming requests was uploaded here (MailServer), and the server code which implements the MTA database back end is uploaded here (CIMMail). I’ve also included the necessary MacOS X scripts to start up a Java server in the background, though it should be fairly simple to create a Windows Service and a Linux script which does the same thing on those platforms.

Forbes on Windows Vista

Dim Vista

Windows Vista: more than five years in the making, more than 50 million lines of code. The result? A vista slightly more inspiring than the one over the town dump. The new slogan is: “The ‘Wow’ Starts Now,” and Microsoft touts new features, many filched shamelessly from Apple’s Macintosh. But as with every previous version, there’s no wow here, not even in ironic quotes. Vista is at best mildly annoying and at worst makes you want to rush to Redmond, Wash. and rip somebody’s liver out.

Vista is a fading theme park with a few new rides, lots of patched-up old ones and bored kids in desperate need of adult supervision running things. If I can find plenty of problems in a matter of hours, why can’t Microsoft? Most likely answer: It did–and it doesn’t care.

Example: If malware somehow gets into your machine, Windows Firewall will not stop it from making outbound Internet connections to do its evil deeds. If you turn off that firewall in favor of a better one, the Windows Firewall control panel will admonish: “Your computer is not protected; turn on Windows Firewall.” But the Windows Security Center will correctly tell you that a firewall is on and that you shouldn’t run two at a time. Call it convistancy.

Gaffes like this make you wonder if security really is improved as much as Microsoft claims. You’ll still have to add your own antivirus software, a new Vista-ready version at that. And Vista’s irritating and repeated warnings about possible security breaches don’t always mean what they say and are usually irrelevant. You’ll take them as seriously as the boy who cried wolf, making them useless as defensive tools.

Ouch.

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.

Finally: uploaded and updated the ASN.1 library.

A while ago, I wrote an LDAP server. Well, nothing as complex as OpenLDAP; just a simple LDAP protocol parser which could translate LDAP requests into requests to modify an internal in-memory data representation of the LDAP database. I actually managed to make it work against a product we were working on at the time.

Part of the problem with that code is that I used the BER ASN.1 library that was part of the Netscape LDAP API library, which while rather interesting, was rather weak in that it was written to be just good enough to deal with the LDAP client spec–and no better. (In fact I had to kludge the hell out of my code to make the LDAP server spec work, as the LDAP server spec is heavy on using the [APPLICATION] tag for just about everything. Turns out there is an ambiguity that had to be dealt with using some odd special-case code.)

So I wrote a replacement library, rewrote my LDAP code to use the new library, and away I went. Someday I’ll post the full LDAP engine, but in the meantime, I finally got around to both documenting my ASN.1 BER parser engine on the Wiki, and uploading the source kit. You can visit the main ASN.1 web page here, or go to the wiki for more information.

Java Swing Stupidity, pt. 1

At some point I intend to write a longish post about various application frameworks and where they lie in a spectrum between “high level” and “low level” verses “easy to use” to “hard to use.” In this scheme Java Swing scores higher than AWT, but lower than MFC.

Meanwhile, I have a hint for those trying to put together a Java Swing dialog and they want the escape key to do, well, what an escape key is supposed to do in a dialog box: hit the ‘cancel’ button and close the dialog.

The head scratching problem:

How do I make the escape key press the cancel button?

Answer:

No, Swing doesn’t do this for you. (Stupid, stupid, stupid.)

Instead, you have to add the escape key handler to the root pane’s input map, and add a new action which triggers the appropriate button click.

To elaborate: suppose you have a dialog class which is creating the cancel button. You need to get the root pane of the dialog, then add a mapping to the root pane from the key stroke you wish to intercept to an “action”, then map the action to a specific AbstractAction derived class that handles the specific action.

// (Inside a method that lives inside a JDialog derived class)
// Create and add my new cancel button.
bctl = new JButton("Cancel");
bctl.addActionListener(this);
bctl.setName("cancel");
contents.add(bctl);

// (New) Create escape key stroke ID, add to input map
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke,"Cancel");
// (New) And add a new action to fire my action object.
getRootPane().getActionMap().put("Cancel", new FireButtonClickAction(bctl));

Note that the class FireButtonClickAction is a new class we create below. It takes an argument to the object we’re clicking, and maps it to the specific action–in this case, an action which presses the cancel button for us.

The FireButtonClickAction class itself is very simple:

final class FireButtonClickAction extends AbstractAction
{
  private AbstractButton  fButton;
  
  FireButtonClickAction(AbstractButton button)
  {
    fButton = button;
  }

  public void actionPerformed(ActionEvent e)
  {
    fButton.requestFocusInWindow();
    fButton.doClick(100);       // 1/10 S press time.
  }
}

I use the doClick(int delay); variant to give visual feedback to the user, as is recommended in the original Apple Human User Interface Guidelines. The 1/10th of a second delay isn’t much, but the quick ‘flash’ does tell the user “your dialog box went away because you dismissed it”, verses “your dialog box just went poof–did it crash?”

You can use the same technique to create ‘meta-keys’ on Windows and Unix; these are generally “Alt+X” key combinations which can be used as a keyboard shortcut to activate the function. (You can also do this on the Macintosh; however, I would recommend against it–or at least against making the underline under the meta key not visible on the Mac as it violates the look and feel and makes your application look like crap.)

I’m live (yay!)

Finally finished the main ChaosInMotion pages.

Of course the work is never done: my LunarPages account was set up to allow me to run JSP pages, and I eventually intend to create and install a bug tracking system as well as other goodies.

But at least my major self-imposed milestone was completed a day early.

I Hate Windows, Pt. 1 (An On-Going Series)

Perhaps this is true for all platforms, but it seems especially true for Microsoft Windows development: because of the number of tricks, code oddities and places where the way things work is completely unclear, it seems that Windows programming experience is measured not so much by length of time, but by the number of battle scars you accumulate fighting some odd little API call or another. You know the feeling: you read MSDN, you make the call you think should work, you’ve got all of the resources in the right place–yet, instead of success you get a null handle or some obscure error code you’ve never heard of.

So off you go to Google, type in the error code–and find about fifty messages in about fifty different sites all saying the same thing: “WTF?” Occassionally suggestions are made–which are about as worthwhile as shaking voodoo sticks and sacrificing chickens to Odin and Thor. Then, finally, you either try shaking your own voodoo sticks or you come across one brief flicker of light amongst the darkness of ignorance–and you discover finally what when wrong. Sometimes it’s an unclear API, or sometimes it’s some odd exception to an existing API that, had you actually had the time to read the entire MSDN article on the subject rather than just skim it looking for the information you need, you would have known about.

Feeling silly and wondering why you didn’t take your mother’s advice to become an Architect, you move on. And another scar hardens on your brain.

I Hate Windows.

As I encounter them, I’ll try to post them here. And I have one that I recently encountered at work with WinCE, though it appears to also apply to the desktop version of Windows.

Where did my help go?

If you press ‘F1’ on your keyboard on Windows, you should get context-sensitive help for your application.

This little bit of magic works by the Windows OS sending your current WinProc an WM_HELP message, which you can then respond to by opening up the on-line help manual to the page which describes the dialog box or window you’re currently working in.

All well and good.

Well, I was converting a bunch of dialog boxes into a tabbed dialog box by using the PropertySheet() call in Microsoft Windows, which worked fairly well.

Except help stopped working.

Scratching my head I discovered that when you live as a property sheet, the callback for your pane looks very much like a DialogProc that you’d pass to DialogBox or some other call like that. Except all of a sudden many messages that have a perfectly valid WM_XXX counterpart–such as WM_HELP–get turned into WM_NOTIFY messages instead.

So, gratuetously, instead of sending you WM_HELP when someone asks for help, you instead get a WM_NOTIFY message with notification code PSN_HELP.

As I was adding the following switch statement to my code:

    case WM_NOTIFY:
    {
        NMHDR *ppsn = (NMHDR *)lParam;
        if (ppsn->code == PSN_HELP) {
            ::SendMessage(hWnd,WM_HELP,0,0);
        } // other notification handlers go here...
    }

I had to wonder–why didn’t Microsoft do this for me? Something perverse? Historic reasons? I dunno, and I suspect resending the message as a WM_HELP message rather than just processing it there at the SendMessage call would be better.

But I wasted a good hour on this one.