So Much for Eclipse

I’ve been using the Eclipse IDE off and on for several years now, mainly because it’s something of a de-facto standard in the Java world, and I want to be something in sync with that world. Well, forget it. I’ve come to the conclusion that the annoyances outweigh the advantages:

  1. The editor is nowhere near as powerful as a stand-alone editor. That should not be a surprise; it’s competing for the attention of the Eclipse dev team with so many other priorities. By contrast, the dev teams working on text editor projects are totally focused on making those editors better.
  2. The editor is sluggish. It doesn’t respond as promptly to my keystrokes as any dedicated text editor I’ve used. This frequently trips me up.
  3. It’s almost as if it has an artificial intelligence engine working away to decide whether or not I’d like auto-completion to be offered for an identifier… and then does precisely the opposite of what I want. The feature pops up unbidden and gets in the way when I’m rapidly typing, yet never appears when I’m paused, trying to remember the precise name of something. Typing Control-Space remedies the latter situation, but still.
  4. Also, the auto-complete for things like parenthesis and quotes is thoroughly evil. It’s always introducing syntax errors into my code, because it comes up slightly too late; by the time it’s gratuitously inserting something, I’ve already gotten a keystroke or two in edgewise.
  5. The default is to indent with hard tabs, and you have to change many settings to defeat this misfeature.
  6. There is no simple, easy way (at least none I’ve found, and I’ve tried) to stop it from making files with lines that have trailing white space.
  7. When upgrading to a new version of Eclipse, nothing is done to import settings settings from any previous version you were using.
  8. When upgrading to a new version, the new version will create a new directory for its workspaces, instead of seeing if there is any existing such area in a default location used by a previous version. The default workspace path changes from version to version. There is no overriding pattern to the defaults.
  9. There’s no way to do something as simple and basic as renaming a project in Eclipse Oxygen. If there is; it’s very well-hidden; the action is not listed in the same menu that creating, deleting, and copying projects are listed.

The straw that broke the camel’s back for me was the mess with the workspace directories. I don’t need three separate, inconsistently-named, locations. Yet that is now what I have. And when I attempted to convert and old workspace into a new one, the conversion failed and left some projects inaccessible. I’m sure there’s a solution that would enable me to fix the problem, but it’s simply not worth continually expending effort at making an overly-complex tool behave itself.

So I’m in the process of reverting to a text editor and using that old reliable standby Ant to do the building of my Java projects. A pity, as some of what Eclipse offers (detection of errors as one types, being able to request auto-completion) really is helpful.

Go (the Computer Language) and Fads

I’ve been looking at the Go programming language recently, because (a) it’s started showing up a lot more in job descriptions, and (b) it combines the interesting attributes of both being compiled to machine language and being garbage-collected.

Unfortunately, it also falls victim to what I regard as an unfortunate fad amongst programming language designers in recent years: the decision that full, preemptive threading is something that programs don’t need and that some sort of ersatz (cooperative) concurrency is good enough.

Well, sorry, in my experience it’s just not. Maybe I’m atypically biased, because of my recent experience writing web crawlers, which have to parse pages as part of the job of finding new links to crawl. That’s a computationally complex task that in certain pathological cases can take indefinitely long. The solution is to run the parsing in a thread, and to kill that thread and proclaim the page unusable if it fails to parse in a reasonable amount of time.

This only works with true preemptive threading. The parsing is taking place in some third-party library that’s stuck in a loop someplace. I don’t want to recode the parsing library and clutter it up with dozens of yield statements. I shouldn’t have to recode it. But absent genuine threads, there is no alternative.

Maybe I’m being unfair here; maybe my experience with concurrency is highly unrepresentative. I don’t know, exactly. I can’t imagine I’m the only person who’s tried to make calls into a computationally complex library routine from a multithreaded program. So color me skeptical about the whole “ersatz threads are good enough” mindset.

I’ll note that C# has both full preemptive threading and the ability to be compiled down to machine code (by default, it’s just byte code, but there is what the C# world calls “ahead of time” compilation, which is just what I described). And C# is not a Microsoft-only thing; there’s Mono.

Demodulating ACARS

ACARS is a digital protocol used by aircraft to transmit messages. It’s been around since the late 1970’s and is decodable using nothing but a sound card and the right software. But, after helping a friend (a technologically-sophisticated one; like me, he has a ham license) who has previously had no luck decoding the messages, it’s clear there’s some tricks involved.

  • Don’t use squelch. Squelch will chop off the first tiny fraction of information in a packet, causing decoding errors (typically, messages simply won’t decode). There’s no need to use squelch, anyhow. Squelch exists to prevent humans from being annoyed by listening to the background noise when a frequency is not in use. Computers don’t care about being forced to analyze static, and can easily distinguish between static and an ACARS packet.
  • Use a wide bandwidth. A big part of my friend’s problem was that he was using the default AM bandwidth on his communications receiver, which was apparently too narrow. I have myself tried using both the wide and narrow filters on my receiver; only the wide one works. ACARS is apparently a wide-bandwidth mode, and a narrow filter throws away critical information needed to decode a message.
  • If using ACARSD, configuration is critical. ACARSD is the most popular freeware package for decoding ACARS. Alas, it’s not exactly user-friendly. To install it you must first configure the installer and manually tell it to create the directories it needs. To configure it you must use a separate program that (re)writes the necessary .INI file. Moreover, that program doesn’t always default to reasonable values as advertised. It claims ACARSD will use the default sound card if none is specified. I found it necessary to explicitly specify the sound card for the default one to be used on my friend’s computer.

How to Disable That Darned Adobe Updater on the Mac

If you ever install Flash, there it will be. A stupid updater process that pops up and runs whenever you least want such a thing to run, typically when your computer is already busy and slow. And the Adobe Updater is itself a booger-eating fat pig that will pork up resources and make your computer run even slower.

There’s no instructions from Adobe on how to remove it. Of course not; they have delusions of grandeur: they think their software is so important that its updater is more important than you are. In fact, they think it’s about the most important thing there is. Definitely more important than Apple’s own update checks, which manage to run unobtrusively and generally when you’re not using the computer much.

Thankfully, it’s easy enough to remove the darned thing. Just open a shell window and type the following commands:

cd ~/Library/LaunchAgents
launchctl remove `basename com.adobe.ARM.* .plist`
rm com.adobe.ARM.*

Et voilà! The Adobe Updater virus program should no longer run itself automatically.

Not to belabor the obvious, but if you choose to do this, it becomes your responsibility to check for and install updates. And with Flash, that’s important, because Flash security fixes come out all the time.

Thanks to the Life of a Computer Scientist blog for coming up with the solution and posting it.

Well… That Was Fun

Not really.

I’ve been working on a set of command-line utilities to let me post here without using an interactive browser. Reason is that WordPress is infected with excessive amounts of crap Javascript, to the point that its editor window is nearly useless if one doesn’t have a solid high-speed connection. Which I often don’t while commuting on the ferry.

Anyhow, two idiots have conspired to make my life more difficult than it needs to be. Both have used an object containing actual or implied time zone information to represent an XML-RPC date/time stamp (which doesn’t contain any time zone information).

Idiot No. 1 wrote the WordPress XML-RPC code (or the PHP library that uses same), and Idiot No. 2 wrote the Apache ws-xmlrpc code. Both idiots made feeble and ultimately failing attempts to defeat the lossage their idiocy begat, and I’ve spent most of the evening puzzling out the gyrations necessary to reverse engineer then counteract the lossage caused by both the base design flaw and the ineffectual original countermeasures… on both the client and server ends.

Yes, I’m being uncharitable and abrasive by calling those programmers “idiots”. You would too if your temper had just been worn thin by dealing with bizarre behavior caused by a stupid design decision.

Beware Replacing os.spawn with subprocess.Popen in Python

This is going to be a very geeky post, but the bug in question just bit me and I am not aware of anyone else having written about it. Worse, the buggy code is actually recommended in the official Python documentation, which claims that the library call:

pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")

Can be replaced with:

pid = subprocess.Popen(["/bin/mycmd", "myarg"]).pid

It can’t. Not unless you want your child processes to mysteriously disappear on you without calls to os.wait() reflecting they’ve completed, that is.

The problem is that the suggested code immediately creates an unreferenced subprocess.Popen object, and this class declares a destructor (i.e. a __del__ method) which automatically reaps exited child processes at GC time. So the code in question creates a race condition as to which code will call os.wait() first: yours, or the destructor.

Arguably, subprocess.Popen should have an option to disable this feature (which is actually the correct behavior if you’re going to hang on to the Popen object and use it to manage the child process). Until such a time the workaround is to do something like:

class PopenNoDel(subprocess.Popen):
  """
  A Popen object that never gratuitously reaps dead children.
  """
  def __del__(self, **kwargs):
    pass

pid = PopenNoDel(["/bin/mycmd", "myarg"]).pid

Thankfully, it didn’t cause me much lost time. I had thought of the recommended code myself, then rejected the idea because of worries about gratuitous process reaping at GC time, and only changed my mind about the idea when the Python manual itself endorsed it. So the cause was fresh in my mind when my child processes started mysteriously vanishing.

Keywords: os.spawn, subprocess.Popen, wait, reap, garbage collector, subprocess, disappear, bug.

Cutting the (Virtual) Cord

I’ve been using Boingo for internet access on the ferry since moving to Bainbridge Island about three years ago.

It’s reasonably priced (about $10 a month), but it’s never been fast. Three years ago, it was easily good enough for reading email with IMAP and sometimes a bit of light web usage. (Pages that had lots of Flash or Javascript never worked well, but simpler ones often worked slow but passably.)

Since then, it’s gotten progressively slower. I long ago given up using a web browser on the ferry and relegated it to IMAP-only use. Then it got harder and harder to even do that; it would take half the trip just to get Boingo to allow me to connect, and it would frequently drop out altogether and make my e-mail client fail.

The exception has been when I tried it on trips other than those at peak commute times. Boingo is surprisingly fast and reliable then (which is mostly irrelevant, since most of my trips are at peak hours). So clearly it’s an issue of capacity and overloading.

One day, while Boingo was giving me the usual frustrations, a new open access point popped up in my Wi-Fi drop-down menu: “Karma Wi-Fi.” It turned out to be a novel marketing strategy by a company that sells cellular internet modems. The connection was faster and more reliable than Boingo had ever been. But the monthly cost was significantly more, so I held off.

Then one evening I did some back of the envelope calculations based on how much my time is worth, and it was clear that the costs of the more expensive service would pay for themselves in about a fortnight. So I’ve taken the plunge, and it’s been as reliable as my free trial was. Time to call Boingo and cancel my service.

Time for Another “Javascript Sucks” Post

For no other reason than it’s been a while since my last one. Oh, I’ve just been bitten by some sucky Javascript today, but that’s hardly new: it happens most days.

That’s because there’s an awful lot of sucky Javascript code out there. Which is the case because Javascript is a difficult language to program well in. Which in turn is the case because both the core language and its object model basically suck.

I mean, how much more sucky a design decision can there be than making all variables by default global unless explicitly made local? This is precisely the opposite of what any sane design would do. Thanks to this misfeature, all the Javascript coder need to is absentmindedly leave off a var or two and presto, there’s a bug waiting to strike. And Javascript’s parallelized and callback-based nature means the bug probably won’t be immediately obvious, so it will make it through testing and into production where it can bite users.

And then there’s the Javascript object model. It’s not necessarily deficient, it’s just bizarre. Well, bizarre to anyone used to the classical inheritance model (which means virtually any other object-oriented language out there); Javascript uses prototypal inheritance. It’s a bit of gratuitous difference that just makes Javascript needlessly strange and thus more difficult to learn and understand for the vast majority of programmers. Why? Just why?

That Javascript makes failure easy and success difficult can be illustrated by how it’s not that hard to run into bad (i.e. flaky and unreliable) Javascript on Google pages. I mean, if one of the largest and wealthiest corporations on the planet, one famous for hiring the best and brightest, one that writes browsers as well as web pages, can’t successfully implement a toolkit to tame Javascript’s bias towards failure outcomes, that’s about as damning an indictment as one can make against Javascript.

Finally, it’s instructive that those who designed the Google Web Toolkit chose to (alas, ineffectively) fight Javascript’s brokenness by writing a tool to enable developers to avoid programming in Javascript entirely.

Javascript code would be bad enough if most of it only had all of the above factors working against it, but wait, there’s more.

First, client-side Javascript has to be cross-browser portable, and there’s lots of gratuitous little differences between the execution environments on different browsers (or even differing versions of the same browser).

Second, many kinds of client-side code, in particular AJAX code, are difficult to write well. Such code must cope well with all sorts of network conditions without adversely impacting human-machine interactivity.

The latter would be difficult to do even with a sanely-designed programming language and execution environment. In Javascript, it’s often close to impossible.

It’s one reason why the answer to the question of how best to do something in client-side Javascript is a simple don’t.

Don’t do it. Not if you can do it in static HTML somehow. It might in some theoretical sense be better to have more interactivity, but in practice a less theoretically-elegant solution that works and works reliability in a wide variety of situations will come out ahead.