2009-11-02

Review: PS3

The day Netflix and Sony announced Netflix streaming videos were coming to the PS3, my 360 died. Not metaphorically; it hung while playing a DVD, and power-cycling got me the red ring of death I thought I'd escaped.

So, after requesting my free repair, in a small act of consumer retaliation, I bought a PS3. I also bought a couple of games: "Prince of Persia", which I'd been considering getting for the 360, and "Uncharted", one of the few PS3 exclusives I could muster any enthusiasm for. (The 360's exclusives are much more my taste; it's no coincidence I bought a 360 shortly after "Halo 3" came out.)

Unboxing
The PS3 slim is much nicer-looking than its "fat" predecessors. It beats the 360 on looks too, mainly because it's just a small black box that you don't really notice. The 360 is a large white box that's pretty hard to ignore. It's slot-loading rather than tray-loading, which I don't really like, but having suffered a flaky tray loader on my original Xbox (Microsoft's hardware screw-up for that generation), maybe it's a blessing. The power and eject buttons are fine; I mention this because the power button on the 360 is mushy and unconvincing, and coupled with the console's slow reaction to a press, happens to be one of the 360's minor annoyances.

The box contains a composite video cable, which is tres fucking lame in 2009. The back of the console does have completely standard HDMI video and TOSLINK audio ports, though, which is a step up from the 360's proprietary crap. There's an ethernet port too; no cable in the box, but the system (unlike the 360) has built in WiFi, so it's perhaps not unreasonable to assume that the kind of old-timers like me who're going to connect a cable already have a house full of the stuff.

The controller connects via USB, but it's wireless, so that's mainly useful for charging. Personally, I'd rather have the 360's non-rechargeable controllers and pay $5/year for a bulk pack of batteries.

There's no power brick. Unlike the 360 and original PS3, both of which really guzzled power, the PS3 slim stays under 100W.

Installation
PS3 installation is the worst consumer electronics installation experience I've had in years. Sony's on-screen keyboard is bad enough (much more fiddly than Microsoft's), but having to use it the first time I turn the device on is worse. (I gave in and connected one of the USB keyboards I had lying around, but the fact I can do that in no way makes up for the fact I felt compelled to.)

If you think the days of being asked to set the date and time were long gone, think again. The PS3 can set the time from the internet, but it won't by default, and even when it does it won't get DST right ("do it manually").

If you think seeing your ethernet interface's MTU is an integral part of setting up any game console, you'll absolutely love the PS3. If you're a general consumer, you'll probably just keep hitting "OK" until it stops pestering you with trivia it should just sort out for itself. If you're in-between, the installer is like something from a UI hall of shame. (Including Sony's own cover of the ever-popular "this setting will take effect after the next reboot".)

Reboot
The console reboots a lot, actually. Or seems to. If you play a DVD, there's a visible "reboot" you don't get with a 360. Luckily, the PS3 does whatever it's doing quicker than the 360 reboots. The orchestra-tuning-up sound that accompanies the "full" reboots is very classy, much nicer than the 360's beeps. (I'd recognize the 360 start-up sound if you played it, but I couldn't sing it. It's totally non-memorable.)

UI
Anyway, when you're finally through the installation torture, you're looking at an Ubuntu-like turd-brown screen. I shit you not. Sure, there are some bits of ash or something drifting across the screen and there's some kind of horizontal brown flow that gives the overall air of a shampoo commercial's "pseudo-science bit". The UI is very much like an uglier version of the PSP interface (which is purple). Where that interface works well on a small screen, I'm unconvinced it scales. Just like the Mac's screen menu bar being genius on small laptop screens but awkwardly distant on a dual-30" setup, Sony's UI works well on a small display where you can take everything in at a glance, but is much less convincing on a huge modern TV, where you feel like you're constantly having to move your eyes.

Poor "dialog" design exacerbates this. Coming from the original Xbox to the 360, I thought this was something that had been solved by the current generation of consoles, but it seems not. The 360 associates actions with buttons, and since each relevant button has a distinct color, the mapping from action to button is easily and clearly signaled by use of a little colored blob representing the button. (That's what it looks like on an SD screen. On an HD screen, you can clearly see the letter, but that's superfluous for anyone with normal color vision.)

Sony's buttons each have a different color, but they seem to be paired: the two horizontal buttons (light pink and dark pink) and the two vertical buttons (pastel blue and pastel green) are quite similar to one another, and it's only the outline of the symbol (circle, square, triangle, and cross) that's colored, rather than the entire button. They're not even filled symbols.

The most distracting part for an outsider, though, is that each dialog's explanation of the buttons is shown in the bottom corners of the (huge!) screen, miles away from where you want to focus your attention. Presumably the habitual PS3 user's response is to tune out this noise, but as a beginner it means I'm slowed down on every decision to confirm that, yes, cross means "OK" and circle means "Cancel". (Though that "OK" might actually mean "Cancel" if you've selected a negative option first, for example in a "quit?" dialog with "yes" and "no" selected by position and "OK" and "Cancel" selected by choice of button.)

The Sony store is a lot less polished than Microsoft's. The front page of PlayStation Home has the overall aesthetic of a C64 bulletin board: a cluttered mess in 8-bit color (the 8-bit blues and yellows really do it).

Why do I mention the store? Readers with long memories will remember that one thing I don't like about the 360 is that it acts like a dipshit compared to the original Xbox. Put in a DVD and the Xbox would play it. Put in a game and the Xbox would play it. The 360 takes you to a screen where you have to press "green" ("A", for black and white viewers, "OK" for users with remotes) to actually play the DVD or game.

By default, the PS3 assumes you want PlayStation Home. That is, you want to see scrolling ads for games you don't have. Great.

Pop in a DVD, and the PS3 will start playing it. Just what I wanted, right? Well, no. Not what I've (for my sins) just popped in a "Star Trek: DS9" or "Battlestar Galactica" DVD, with multiple episodes. If you watch one episode per night, it's annoying having the console start playing the first episode on the disc every night. It wouldn't kill it to remember where I left off.

I have the 360 remote, so it's not fair to compare that aspect of using the PS3 as a DVD player, but I read that the PS3 remote doesn't have backlit buttons, and eats batteries, which isn't encouraging. (I haven't had to change the batteries in the 360 remote yet, and it does have backlit buttons, which is useful when you're watching DVDs in the dark.)

The stupid behavior with multi-episode discs is probably going to keep the PS3 from becoming my default DVD player.

Actually, there's one positive thing I can say about the PS3 as a DVD player. It's well known that the 360 uses a lot of power, and power means heat, and heat means fan noise. I'd stopped noticing the noise the 360 makes, without even realizing. It took me several minutes to work out what I found unnerving about watching a DVD on the PS3: it's too quiet. I can't hear the console at all. As a long-term 360 user, my subconscious conclusion was "something must be wrong".

Games
I forgot to mention how things play out immediately after the device installation. You've been through all this unnecessary bullshit, and you pop your game disc in and... you're told you need to download an update. Okay, that's not too different from the 360, except the updates seem much bigger. So you have the "downloading" progress bar and then the "installing" progress bar, and then the game starts... and you get another progress bar. Another long one. My assumption, having read reviews back when the PS3 first came out, is that this is something to do with caching stuff onto hard disk. But there's nothing to tell you what's going on, not even "loading...", and it's slow. When it finishes, comically enough, then you get "loading..." and another progress bar.

I'd be curious to know why they didn't just implement a regular cache, or even background prefetching during play, instead of this weird pre-play stop-the-world prefetching. (Start Halo after spending different amounts of time at the loading screen after boot to see masters at work.)

Games look about the same as 360 games. "Prince of Persia" looks exactly like a 360 game, and "Uncharted" looks kind of crappy by 2009's standards, but okay for a 2007 game, which is fair enough, because that's exactly what it is.

Games also have a bizarre habit of starting by telling you that a particular icon means "saving progress" and that you shouldn't turn your console off. The two I have actually wait for you to acknowledge this "helpful" tip, and they're not doing anything useful while they wait. The "loading..." progress bar comes after you acknowledge. (The 360 solves this by using text instead of an icon, and saying something like "Saving progress. Do not turn off console." Sometimes a few words are worth a lot more than an icon no-one recognizes.)

Controller
The controller is too small. It's like a miniature controller for tiny little girl hands. "Uncharted" uses what 360 users would call the bumpers as triggers, perhaps because the PS3 controller doesn't really have triggers. It has buttons where the triggers should be, but they're not long enough, and they curve the wrong way: they're convex rather than concave! That neither of the two games in my extensive survey really use the triggers for anything suggests that everyone knows the controller's triggers are fucked beyond repair. (Sony even calls them L2 and R2, the bumper buttons being L1 and R1.)

I find the analog sticks harder to use too, but I'm not sure if that's lack of practice, or that one of them is in the wrong place (the left analog stick is swapped with the d-pad), or that the controller as a whole is too small, or that the analog sticks aren't as good.

Microsoft (or Sony) could sell me a 360-like controller for the PS3 in a flash. Japanese miniaturization is all well and good, but I need a full-sized controller. With proper bloody triggers.

How can they sell a game like "Rainbow Six" on this platform without including a custom controller? Or is there some secret about plugging in a keyboard and mouse and pretending you're a PC gamer no-one's told me about?

Summary
The PS3 is more invisible than the 360 (both in appearance and noise), games seem about the same (though the 360 has better exclusives), the 360 is a better DVD player and has a better controller.

I was hoping to be more won over by the PS3. I'd have liked to relegate the 360 to "second console", brought out only for future 360 exclusives. (Assuming there are any more interesting ones before it's time for the next generation.) As it is, I don't think the 360 will find it hard to retake its place, though it's weak that my main problems could be fixed in software (UI fiddliness, DVD retardation) and by selling optional better peripherals (controller and remote).

As for the games, "Prince of Persia" is great fun if you liked collecting orbs in "Crackdown", the middle-east theme of "Assassin's Creed", and the improbable momentum-defying acrobatics of both. Don't tell Sgt. Johnson, but I'm actually enjoying spending my time with a frigging fairy princess. "Uncharted", well, it's okay, but there's nothing in the first hour to make me want to play any more until I've finished "Prince of Persia".

2009-10-04

Giving up on .dmg

Alexander Limi recently wrote Improving the Mac installer for Firefox (and also a part 2), where he basically explains all the ways in which .dmg is an awful choice.

John Gruber followed up with How Should Mac Apps Be Distributed?, in which he praised "the resurgent trend of delivering Mac apps as simple .zip archives".

It's not like .dmg hasn't always been awful; in 2006, Cédric Luthi 's zip vs dmg complained about how slow .dmg is compared to .zip, and though he could have better emphasized that he meant the awkwardness of the entire process rather than just CPU time, it's clear he was really talking about the same problem.

The jessies.org applications have been shipped as .dmg files for years now, and since most of us build from svn and run straight from the file system, we don't often feel the pain of installation. Watching others struggle with .dmg, though, is a pretty convincing argument that this madness be stopped, Apple's recommendations be damned.

It's worth noting that Apple doesn't have to suffer its own recommendation, because Apple's stuff either uses .pkg or is installed with the OS [using .pkg behind the scenes] and updated by Software Update.

We've also had trouble since 10.5 with occasional bogus "the disk image you are opening may be damaged" messages. These are repeatable on any given machine, but the MD5 of the downloaded bits is exactly the same as on another machine where everything works fine. And later builds seem to work on machines that have had problems previously, and new machines that used to be fine start having trouble. This hasn't been fixed by 10.6. It doesn't seem to matter whether the .dmg is generated on 10.4, 10.5, or 10.6. (As far as I know, we've never seen the warning on a 10.4 machine, so whatever the bug introduced in 10.5 is, it wasn't included in 10.4 security updates.)

Anyway, so many people finally standing up and agreeing that the emperor has no clothes has given me the courage to revisit what I said in 2007's Choosing the best disk image format on Mac OS, where .zip was the clear winner even if it wasn't taken seriously as a contestant, and switch us over to .zip.

2009-09-21

Review: "JavaScript: The Good Parts"

JavaScript has always been a bit of a mystery to me. Every time I've had any contact with it, I've been left wondering why anyone in their right mind would have anything to do with it. Let alone what kind of criminal mind would have originally conceived of such an abortion. I've never found (or heard tell of) anything good about it, other than its ubiquity. The fact that JavaScript is built in to every browser, but no alternative is. As far as I can tell, it's this ubiquity that helps JavaScript cling to life like a daglock, despite being little more than hair matted with dried shite.

I've always been curious, though, if only thanks to a weak belief in the "no-one's useless; they can always serve as a bad example" principle. So when I stumbled across a book with the title "JavaScript: The Good Parts", I thought I'd take a look.

It is, as you'd imagine, a very slim volume. It's about 140 pages, but even that exaggerates the amount of content. There's plenty of whitespace in the book (a good thing) and many things are taken too slowly (a bad thing, because many tricky things are taken too fast).

It starts off quite amusingly, but as early as page 3 I was starting to worry about the author. The verse numbering here is my own. In the original, this is one paragraph with no breaks:

1. The fashion in most programming languages today demands strong typing.

2. The theory is that strong typing allows a compiler to detect a large class of errors at compile time. The sooner we can detect and repair errors, the less they cost us.

3. JavaScript is a loosely typed language, so JavaScript compilers are unable to detect type errors. This can be alarming to people who are coming to JavaScript from strongly typed languages.

4. But it turns out that strong typing does not eliminate the need for careful testing.

5. And I have found in my work that the sorts of errors that strong type checking finds are not the errors I worry about.

6. On the other hand, I find loose type checking to be liberating. I don't need to form complex class hierarchies.

7. And I never have to cast or wrestle with the type system to get the behavior that I want.

You'll notice he starts off in verse 1 with a unsubstantiated pejorative that "fashion demands" strong typing. Not that programmers find it useful. No, "fashion" "demands" it.

He mentions the "theory" of "strong typing" like a creationist might mention the "theory" of "evolution", without bothering to point out which of the logical steps in his presentation of the "theory" he considers to be incorrect.

I assume it's the devil who puts errors in our code.

Actually, while we're going with this analogy, let's throw in the old "missing link" fallacy: verse 4 helpfully points out that stronger typing can't catch all errors. As if anyone ever claimed it would.

We're given no details of what proportion of errors are type errors, or whether it's more efficient (by any metric) to catch those errors via type signatures/annotations than via manually writing unit tests (which, of course, also contain errors).

In verse 5, we have a nice example of "argument by anecdote" made especially worthless by the rather vague term "errors I worry about". Note that he doesn't say "errors I make" or "errors commonly made by a cross-section of programmers". He says "errors I worry about". Does this mean he's happy to ignore type errors? Or that JavaScript gives him so many opportunities for new classes of error (like scope errors and binding errors and whitespace errors and RTTI errors and floating point arithmetic errors and equality errors and so on) that he just doesn't have time to worry about old-fashioned stuff like type errors that people writing code in sane languages have the luxury of concerning themselves with? Who knows?

Verse 6, without examples, would appear to be an admission that the author isn't any good at class-based OO programming. I'm not sure what the relevance is, other than a warning to the reader.

I realize this dissection of a single paragraph is of only tangential relevance to the book review this is supposed to be. But I'm sick of hearing this same old crap time and time again. You want to fight? Okay, let's fight. But let's fight with science, like grown ups. Fighting with religion like mystics is demeaning to us both, and fundamentally pointless. Show me the data, or shut the fuck up.

I left verse 7 in to show that I'd like to be above this kind of name-calling. He has a point, that most type systems aren't as expressive as we'd like at times. But there are notable exceptions, and whenever I see a "loose typist" say things like this, I think "there goes someone who had the misfortune never to have used Haskell or SML or whatever". Sure, all popular languages' type systems have their weaknesses, but I don't understand why anyone would assume that the solution is to throw the whole thing out. It's not like we have proof that the problem can't be satisfactorily solved. Or that, returning to the horse you thought I'd already flogged quite to death, that half an eye isn't better than no eye. Quite the opposite.

And it's not like anyone bothers to back up their anti-type system prejudice with any research. Do we stop testing because testing can't catch all errors, or do we try harder, and use other things to help us catch errors too?

The onus is on the "loose typists" to demonstrate that they're not crazy, which is exactly why they always resort to this kind of sophistry. It's so much easier.

(As a final aside before I return to the book, many of the best programmers I know understand programs via the types. This too is often overlooked by "loose typists", and sometimes leads me to wonder if there's a deeper difference in the way the two groups see, understand, and reason about the world. In which case demonstrating, say, a software-quality superiority of one style over the other would solve nothing.)

Anyway, ignoring the nonsense – bad sign though it is, when setting out one's stall – and turning the page, that's chapter 1 ("Good Parts") done with. On to "Grammar", a chapter which takes 15 pages, mostly consumed by "railroad diagrams" of the kind used in Pascal textbooks from the 1980s, bizarrely enough. Sadly, these are even harder to read than the traditional kind because there are no arrowheads on the arcs. You're faced with directed graphs where you have to work out the directionality yourself.

How very fitting.

I don't understand why some variant of BNF wasn't used. This book is aimed at people who can already program, so it wouldn't seem unreasonable to assume they can already read a variant of BNF, or learn one in a couple of paragraphs. (If you make it to the end, pages 125-135 repeat the diagrams from this chapter, to no particular advantage.) But don't skip this chapter: in between the diagrams there are many important gotchas revealed. If you noticed me talk about "whitespace errors" earlier, for example, read the section on "return" and weep. (Though note that the text here is misleading. There's a clearer and more accurate explanation later in the book. So on second thoughts, maybe you should skip this chapter after all.)

Skipping ahead to page 36, we learn that the one thing JavaScript appears superficially to have got right, C-like syntax, is also fundamentally broken. Those curly-brace delimited blocks don't introduce a new scope. Strangely, the chapter spends more time on currying and memoization than it does on this, which is one of the things so broken about JavaScript that I'd heard of it even before reading the book. Currying and memoization are presented seemingly for their coolness rather than their usefulness to JavaScript programmers. If you want to be a functional programmer, I can't think of a worse language than JavaScript. And if you must run in a browser, real functional programmers are smart enough to write SML-to-JavaScript compilers in Haskell anyway. (Given a decade and a handful of PhD students.)

Chapter 5 talks about how JavaScript's prototype-based system of inheritance is "more expressive" than the usual class-based systems. Without, of course, dwelling on why class-based systems are more common. Or why previous prototype-based systems (NewtonScript, say, or Self) never went anywhere. No. What we have instead is a section that explains how to imitate class-based inheritance (but pointing out that it doesn't really work out thanks to some bad decisions in JavaScript's design), a so-called "functional" scheme whose purpose is seemingly to paper over the lack of privacy in JavaScript, and a presentation of mixins by a JavaScript-specific name ("parts").

The "Arrays" chapter seems to claim that arrays are really just maps, and hence slower than you'd imagine an array to be, but surely that's a quality of implementation detail? Surely an implementation is free to special-case the (presumably common) case where the keys are consecutive (or at least dense) integers? The "delete" operator is weird (I don't like Python's either), while the "splice" method just seems badly-named. The "splice" method also seems like a good example of how loose typing seduces people into making one method do too much. For an array "for in" is even more screwed up than we've already been shown it is for objects. Strangely, JavaScript seems to have no range type or literals, so you're reduced to:

var i;
var v;
for (i = 0; i < array.length; ++i) {
v = array[i];
// ...
}

Going back to the lack of block scope, you could move the "var v" inside the "for" loop, but it would mean the same as the code shown here, and thus be more confusing.

(You'll note I'm left speculating about a lot of things. The author doesn't really go into implementation issues, and when he does, he doesn't actually come across as someone intimately familiar with the implementations anyway.)

Page 61 contains the kind of code that makes you not want to work with its author. It shows you how to write a home-made heuristic test for whether a given object is really an array. Why, you might wonder, would someone who doesn't go in for type systems care? So they can "write functions that do one thing when passed a single value and lots of things when passed an array of values". Except these functions won't be 100% sure they've really got an array. Cunning plan, Baldrick.

There follows more wishful thinking along functional programming lines, leaving me honestly curious to know how much this crops up in the stuff JavaScript's actually used for. Or maybe JavaScript programmers spend most of their time fantasizing that they're actually programming in some other language. A language that doesn't suck.

Odd though it may seem to have a single 12-page chapter on regular expressions that doesn't really deal with language-specific quirks, there's one in this book. I doubt that anyone who didn't understand regular expressions going in could gain much from the presentation, and given there was nothing of value for people who already know regular expressions (beyond the fact of the Ruby-like slash-delimited syntax and the exact details of the three possible trailing flags), I'm not sure what purpose this chapter serves.

Chapter 8 is a nice brief summary of the built-in types' methods, though much space is wasted on implementing functions in terms of each other. Here's most of the author's explanation of push, for example:

Array.method('push', function () {
this.splice.apply(
this,
[this.length, 0].
concat(Array.prototype.slice.apply(arguments)));
return this.length;
});

I'm sure that's really helpful.

Some of the text in this chapter (which is otherwise pretty clear and to the point) is annoyingly vague, too. We're told, for example, that "shift is usually much slower than pop", but what does that mean? That some implementations back arrays with vectors but other ones use dequeues? That bad implementations use arrays and good ones dequeues? That standards-conforming ones use arrays and non-conforming ones use dequeues? Something else entirely? (You'll recall that we were told in the beginning of chapter 6 that JavaScript arrays are more like hashes, though there too we were left on our own as to what that really means.)

I mentioned earlier that JavaScript doesn't have a range type, which means that counted loops end up written out in longhand. In this book, they're even longer than usual, looking like this:

for (i = 0; i < 4; i += 1) {
...
}

Not because JavaScript doesn't have operator++. It does. But Crockford doesn't like operator++: they "have been known to contribute to bad code by encouraging excessive trickiness" and "are second only to faulty architecture in enabling viruses and other security menaces" (page 122). Is this true of JavaScript? We're given no reason to believe it is. There's a longer version of this same madness on page 112:

The increment and decrement operators make it possible to write in an extremely terse style. In languages such as C, they made it possible to write one-liners that could do string copies:

for (p = src, q = dst; !*p; p++, q++) *q = *p;

They also encourage a programming style that, as it turns out, is reckless. Most of the buffer overrun bugs that created terrible security vulnerabilities were due to code like this.

In my own practice, I observed that when I used ++ and --, my code tended to be too tight, too tricky, too cryptic. So, as a matter of discipline, I don't use them any more. I think that as a result, my coding style has become cleaner.

Allow that to sink in for a moment.

Nice way to destroy your own credibility, dude. I mean, there may be some terrible problem with JavaScript's ++ and --, but if there is, he's completely failed to tell us what it is. He's asserted that it's a bad thing in C, but this isn't a book about C. This is a book about JavaScript.

And, since I'm already shouting and red in the face, I'll add that what he says isn't true of C, either. It's not the increment of an index or pointer that's the problem: it's the lack of a bounds check before using the index or pointer. If you're not sure who to believe, Mr Published Expert or me, Random Internet Guy, ask yourself this simple question: would an incorrect C program with a buffer overrun be fixed by switching from "++" to "+= 1"? Would the buffer overrun have been less likely in any way, shape, or form if the programmer had used "+= 1" instead of "++"? Of course not.

By this kind of bogus "logic", I shouldn't use the word "gift" in English, because "Gift" means "poison" in German, and, as you know, most of the poisonings that cause terrible illnesses in people are due to poison.

I haven't been subjected to such utter gobshite in a computer book since I gave up on Herbert Schildt.

If you've got a stomach for tripe, and you still think you might like this book, I'd recommend a glance at appendix E, which contains an implementation, presumably Crockford's, of a JSON parser. There's a "break" indented 9 levels and inside a loop made more readable by saying "i += 1" instead of "++i", of course; along with an assignment and a "delete" statement in another loop, both indented another 9 levels. I'll grant you it's a crude measure, but as far as style goes, deepest level of indentation is a pretty reliable indicator of a programmer's taste, and this man has absolutely none.

In fact, if you're seriously considering wasting money on this book, I strongly recommend you look at the last page of content (page 145), and the function on it. If you think the opinions of the man who wrote that code in a book primarily about style are worth your time, you need more help than any book can offer. There may be parts of the function that are, thanks to JavaScript's awfulness, unavoidably bad. But there are parts that could be trivially improved. (See the big comment for one hint; never say in comments what you can say in code!) And there are other seemingly obvious improvements that if they're not valid, it would really be worth explaining why not. For example: the author repeatedly tells us that JavaScript's for-each is broken and you need to make a hasOwnProperty test too, and the author has a huge hard-on for functional programming in all kinds of places where it doesn't help, but he won't write a higher-order forEach function?

Bah.

I still think the idea behind "JavaScript: The Good Parts" was a good one, but the implementation was flawed, and the author was perhaps not a man suited to the task. The language itself may or may not actually have enough good parts to leave a working language behind if you really did avoid the bad parts, but Douglas Crockford is not a man of sufficient perspicacity for us to find out.

If this book had been a blog post somewhere, I could have happily passed over it with little more than a "meh". But the thought that those bastards over at O'Reilly killed trees for this, and unknowing punters like you or me give them money for it... Unrelated to this, someone at work the other day claimed that O'Reilly hadn't printed a decent book in the last ten years, and there was general agreement. I asked that "Java Generics and Collections" be considered the sole exception, but it's bumf like this that's ruined/ruining O'Reilly's reputation.

So what did I learn about JavaScript? That I'm never going any closer to it than the sensible end of a AnythingButJavaScript-to-JavaScript compiler. And I shall do my best to avoid even that.

2009-09-06

Farewell to Java 5?

You've probably read that Mac OS 10.6 has finally made Java 6 the default, and you may also have read that there are both 32-bit and 64-bit JVMs. (That latter part will only seem surprising to you if you'd been using Java 6 on 10.5.)

What I didn't know until I read Things Removed in Snow Leopard was that Java 1.4 and Java 5 have actually been removed from 10.5. (Cocoa-Java has been removed too, but we were told to stop using that years ago, and we know that what Apple deprecates in one version, Apple tends to remove in the next.)

If you've been paying attention to Ubuntu 9.10 – which I hadn't, but someone else pointed this out – a quick sun-java5-jre package search shows that while Ubuntu 9.04 ("jaunty") offered the sun-java5-jre package, 9.10 ("karmic") doesn't. Both have Java 6 though: compare the sun-java6-jre package search.

In the Ubuntu case, you'll still be able to install a Java 5 JDK/JRE downloaded direct from Sun, but in terms of ease (and likely default), it looks like we're finally entering a Java 6 world.

The people least likely to be happy about this are those running Java applications on a Unix box, displaying on a Cygwin X11 server. Sun's Java 6 and Cygwin's X11 server really don't get on well.

Mac OS 10.4 users might not be too happy as apps start requiring Java 6 since for them that means an OS upgrade: there are no practical third-party JVMs they can use. And for some, an OS upgrade will entail a hardware upgrade because 10.6 is the first version that doesn't support PowerPC. But now these users are two major OS releases behind, Apple's "deprecate one, remove one" tempo means lots of stuff's going to start breaking for them anyway.

I'll be curious to see what happens to the Omni Software Update Statistics over the next couple of months. For 10.5 to have only overtaken 10.4 in 2009-02 is quite shocking for a group so traditionally upgrade-rabid as Mac users. (Though these numbers aren't necessarily representative of all Mac users.)

2009-08-21

Java on a thousand cores

Cliff Click wrote a recent blog post that started "warning: no technical content", which wasn't true. Buried 3/4 of the way through was a link to the PDF slides for the "Java on 1000 cores" talk he's been giving recently. I was in the audience of the specific instance of the talk he mentioned, but if you weren't, you can now watch the video on YouTube.

I tend to avoid talks because so many of them are a complete waste of time. This one, though, was so good it had me thinking about why I've mostly given up on talks.

For one thing, most speakers speak far too slowly. I know one of the rules everyone's taught about public speaking is to speak more slowly. That because you're nervous you'll speak faster than you realize, and that sounds like you're rushing, and that's bad. Which might have made sense in the 1700s when public speaking likely meant boring your congregation to sleep every Sunday morning, where the point was less the content than the submission to authority. Going slow might make sense if you're trying to educate beginners (though there I think repetition and usage is what matters, not slow presentation). I can even admit that going slow is downright necessary if you're walking someone through a physical procedure, but it's an awful way to present summaries or reviews (in the sense of "review paper"). And most talks are, one way or another, summaries or reviews.

As if looking for a less literal way in which they can speak too slowly, few speakers have a good feel for how many words any particular point deserves. You know these people. You've been in their talks. These people have their four obvious bullet points on their slide, four bullet points that you grasp in the second or two after the slide is up, and somehow they manage to spend five minutes laboriously wading their way through these points while adding nothing to your understanding. And all the time, you stare at the screen willing the next slide to appear. Wishing you'd brought your Apple remote. (They're not paired by default, you know.)

Don't be afraid to have a lot of stuff on your slides, either. The people who tell you not to have more than a couple of points per slide have nothing to say. At best, they're salesmen. (See Steve Jobs' slides and presentations. Things of beauty both, but designed for selling, not transfer of technical information and ideas.) The naysayers also assume you're making all the usual mistakes too, when they should instead tell you to speak fast and only speak useful words, in which case it won't matter how much stuff is on each slide, because no-one will be bored enough that they're sat there just reading the slides. If they're not listening, taking away the slides is not a fix for your problem.

Another bad habit is not asking anything of your audience. I don't mean questions. I mean prerequisites. Seriously, those five people at your talk about building STL-like containers who don't know what the STL is? Tell them to fuck off and stop wasting everybody's time. Or, if you think that's a bit much, just start with "this talk assumes a basic familiarity with X, Y, and Z; if you don't have this, I'm afraid you probably won't get much out of this talk". You're not helping anyone by spending ten minutes rambling on about stuff that anyone who's going to get anything out of your talk already knows anyway. Unless you're someone like Steve Jones, you probably don't need to explain science to the layman. It's much more likely you're talking to an audience of your peers, and you should respect their time as you'd expect them to respect yours.

Also, please don't waste my time with talks where the only thing I learn is how much you like the sound of your own voice, or talks that only exist because you get some kind of merit badge for having given a talk. In the former case, get a blog. Then people can decide for themselves whether they like the sound of your voice, and subscribe if they do and ignore you if they don't. In the merit badge case, corporate life is full of bogus achievements; I'm sure you can find one that minimizes waste of other people's time. Hell, if it helps, I'll make you a little "I didn't waste anyone's time giving a gobshite talk" certificate.

Et cetera.

Anyway, getting back to Cliff Click's talk... his was a great example of what talks should be like. His content was interesting and concentrated. He assumed his audience knew the basics of the areas he was talking about. He spoke fast. Fast enough that I was often still digesting his previous point while he was on to the next. (And for all you MBAs: this is a good thing. Better too much content than too little. I can always re-read the slides/re-watch the video afterwards. And sometimes thinking about the last thing I was interested in helps me coast through a bit I'm less interested in.)

One thing I particularly like about Cliff Click's stuff in general is his practitioner's point of view. He asks the important practical questions: "Have you successfully built one?", "Did it do what you expected?", "What is it good for?", "What isn't it good for?", "Is it worth it?".

As for this particular talk, there were several new ideas to me (I hadn't heard of the optimistic escape detection [as opposed to escape analysis] he mentioned in passing, for example), several things I found surprising (that write buffers turned out to be unimportant with Azul's CLZ [unrelated to ARM's CLZ], for example), and a lot of familiar stories about mixed hardware-software designs, interesting mainly because it hadn't occurred to me that they might be common to all hardware-software companies.

Plus it was a model of how to give a good talk.

2009-07-27

Removing the title bar from your Android Activity

Sometimes you have a good use for the title bar – the gray strip beneath the system status bar – in your Android app. The Gmail app, for example, uses it to tell you which folder you're looking at and how many threads with unread mails are in that folder, for instance: "Inbox (52)".

Other times, you've got nothing worth saying. If you're actually using it as a title bar rather than as a status bar, you're probably wasting precious screen space that could be used for more context or bigger (easier to hit) buttons or something.

If you ask the internets, the usual advice is to call requestWindowFeature in onCreate:

  @Override public void onCreate(Bundle state) {
    ...
    requestWindowFeature(Window.FEATURE_NO_TITLE);

This works, but it's really meant for the exceedingly rare case when you don't know ahead of time whether or not you want a title bar. If you do know, you're better off saying so in your AndroidManifest.xml:

...
  <activity android:name=".MyMainClass"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar">
...

(You can specify the theme on a per-activity or per-application basis.)

To see the advantage of this, compare what happens when you first start an app that uses each method. In the requestWindowFeature case, the system provides a title bar announcing your app name until the code to turn it off is actually run a few hundred milliseconds later. If you then go back to the home screen and re-enter the app, the title bar is already gone. So not only does this scheme look rather sloppy, it's not even consistent.

In the AndroidManifest.xml case, though, you never get a title bar. Your app looks the same whether it's starting afresh or simply un-pausing, never looks like it's been caught with its pants down, and psychologically (to me at least) feels like it's starting faster. Or at least as if the pause is the system's fault, rather than your app's fault.

(It seems likely to me that part of the reason the worse solution is so popular is that it's mentioned in the developer.android.com FAQ. I've sent a patch.)

2009-07-16

Why find(1) doesn't like big directories

A friend had trouble recently trying to use find(1) on a directory containing millions of entries. He expected it to start pumping out results straight away, but found instead that it went away for a long time. A quick strace(1) showed it steadily reading directory entries.

We could speculate about what's going on, or we could look at the source. Let's start by finding find(1):

$ which find
/usr/bin/find

Then we ask the Debian packaging system which package installed that file:

$ dpkg -S /usr/bin/find
findutils: /usr/bin/find

And then we ask for the source code for that package:

$ cd /tmp
$ apt-get source findutils

A quick search for "opendir", "readdir", and "closedir" – the three POSIX functions responsible for directory iteration – suggests lib/savedirinfo.c as a likely candidate, and if you look at xsavedir in that file, you'll see that it does indeed iterate over the entire directory and returns an array of all the entries to its caller.

Easily fixed, right? If we're not sorting, there's no reason to return a collection rather than an iterator, and any caller who wants to sort can still implement that on top of the iterator. Conversely, you can't implement a low-memory or low-latency iterator on top of a collection (because you've already paid for all the memory and all the latency while building the collection), nor can you implement a cheap "isEmpty" that reads at most three directory entries (three because you may get "." and "..", neither of which count).

In the single-directory case, an iterator probably is the way to go. But things aren't so simple in general, which is why most modern APIs, though built on the POSIX iterator primitives, offer a collection.

Suppose you're implementing find(1) using iterators. And suppose, for simplicity's sake, you're doing a depth-first traversal. What do you do when you come to a child directory? Well, the important part is that you create a new iterator for that child's entries. And if it has child directories, you'll do the same for them. So what?

Memory isn't the scarce resource here. File descriptors are. Specifically, the one opendir(3) needs for each directory between the directory you started in and the deepest directory. Your new pathological case then is a deep directory tree. How deep? The default per-process limit on my Ubuntu 9.04 box appears to be 1024 file descriptors. And remember that your program is probably already using a bunch of file descriptors, and that most code doesn't cope well with running out of them.

You can increase this limit (the separate per-system limit is sufficiently high that you probably don't need to worry about it), but then all programs using the iterator-based code to walk a file tree needs to worry about setting this.

You can try the trick of keeping an explicit stack of iterators and closing old ones if you feel you've used too many, re-creating them when you recurse back up. See telldir(3) and seekdir(3) for how you might implement this or nftw(3) for an API that actually works like this. Note that the OpenBSD nftw(3) just ignores the file descriptor limit (i.e. it uses the naive approach) while glibc 2.9 uses a hybrid approach of collecting all remaining entries for each iterator (that is, file descriptor) it has to close.

So, yeah, it's a bit more awkward than it looks.

Still, there's little excuse for non-recursive non-sorting ls(1) to have the same behavior, but it does (and if you look at the source for that, you'll see it's got pretty much the same code as find(1) to collect all the entries before touching any of them). Is not the main reason for "ls -U" the fact that sometimes you have really big directories and just want the names as quick as possible?

2009-06-11

jvisualvm

For some reason, I was under the impression that jvisualvm(1) was just a rebranding of jconsole(1). It turns out that it isn't, and that – unlike jconsole(1) – it's not a waste of space.

It's not very clever about dividing up space between its various graphs, but other than that it looks pretty nice. I thought I wanted a quick heap profile to see why one of my applications ate so much memory that my machine always felt swappy afterwards. When jvisualvm(1) showed that there wasn't much heap retention going on, I was almost ready to dismiss it as broken, but thought I'd play about and see what else it could do. Turning to the "threads" tab, I saw my actual problem: I had several hundred idle threads.

It turned out I'd once again forgotten that "an unused ExecutorService should be shut down to allow reclamation of its resources".

I had code like this (only without the call to shutdown):

  ExecutorService service = Executors.newFixedThreadPool(threadCount);
  for (Input input : inputs) {
    service.execute(new Job(input));
  }
  service.shutdown();

Every time this ran, which was pretty frequently, I'd leak another 8 or so threads, that I'd never use again.

I should write myself some kind of "do this batch of jobs on n threads and then kill the threads" wrapper.

Anyway, although I was disappointed not to find any heap retention in any of my applications, I was quite pleased with jvisualvm(1) for finding a performance problem, even though it would have been as easy to spot with control-\ — I think that having all the tools together in one place makes me a bit more likely to bother to poke about now and again.

If you have trouble installing plugins like VisualGC, try quitting and restarting. I found that – contrary to the error message – they had actually installed okay, and appeared in the UI when I restarted. They even seem to work.

2009-06-10

xargs -P

Another entry in my occasional series of options Unix never had when I were a lad (last time: tail -F)...

I needed to use xargs(1) the other day to run lots of really cheap jobs, each of which had a high latency.

This was taking a long time until a friendly youngster suggested I use GNU xargs' -P option. Starting again with -P 32, my job finished in less time than I'd already wasted.

2009-06-08

Mac OS 10.6

I'm pleased to see Mac OS 10.6 is coming in September 2009, and I'm pleased it's going to be $29 instead of $129, because most Mac users I know stuck with 10.4 which was "good enough" and which they'd already paid for.

I'm slightly surprised by the "Mac computer with an Intel processor" requirement. At least I won't have to feel quite as bad about dropping PowerPC support myself.

I'm disappointed at the lack of detail about Java. "Complete Java JDK, including javac, javadoc, ANT, and Maven tools" doesn't tell me whether Java 6 will finally be the default, which is what I'm hoping for. PowerPC support doesn't cost me much (except the ability to build on 10.4 or 10.5 with the same make rules, which isn't a big problem as long as all the Mac OS-using developers are still on 10.4).

But being tied to Java 5 is increasingly annoying (and limiting). Reflection and other hacks only get you so far, and -source 1.5 doesn't protect you against accidentally using API that wasn't in Java 5 — String.isEmpty having caught me out just yesterday.