Archive for September 2007

Selecting Text

September 26, 2007

Here’s a helpful MacOSX feature that I finally stumbled upon. If you hold option down while selecting text, you can select an arbitrary rectangle, instead of some number of rows. A picture is worth a lot of words:
Column Selection Example
This is great for removing extraneous information from console logs (pictured), or copying just what you want. Unfortunately, it does not work in all applications, including Safari and Terminal. A damn shame, but it works like a charm with Xcode, Console, and TextEdit.

(NS)AppleScript Sucks

September 24, 2007

EDITED TO ADD 2007-11-02: Some of the issues discussed in this article, like Script Editor messing with your code, have been addressed in Leopard. But until the majority of OS X users are on Leopard, they’re still a problem for most people. Also, I think it’s worth documenting just how many issues AppleScript tools and support have had. So I am not planning on removing “fixed” problems, at least for a while. This article is about why I don’t like using AppleScript. Historical issues are part of that dislike. It’s a matter of trust and expectations.

The NSAppleScript honeymoon is over. I don’t like AppleScript, I don’t like NSAppleScript.

John Grubber has a good article on AppleScript’s “natural language” failings. An excerpt (emphasis mine):

INTERPOLATION ON THE FAILED EXPERIMENT THAT IS APPLESCRIPT’S ENGLISH-LIKE SYNTAX

… It was a grand and noble idea to create an English-like programming language, one that would seem approachable and unintimidating to the common user. But in this regard, AppleScript has proven to be a miserable and utter failure.

In English, these two statements ought to be considered synonymous:

path of fonts folder of user domain
path to fonts folder from user domain
But in AppleScript, they are not, and rather are brittlely dependent on the current context…

The idea was, and I suppose still is, that AppleScript’s English-like facade frees you from worrying about computer-science-y jargon like classes and objects and properties and commands, and allows you to just say what you mean and have it just work.

But saying what you mean, in English, almost never “just works” and compiles successfully as AppleScript, and so to be productive you still have to understand all of the ways that AppleScript actually works. But this is difficult, because the language syntax is optimized for English-likeness, rather than being optimized for making it clear just what the fuck is actually going on.

This is why Python and JavaScript, two other scripting language of roughly the same vintage as AppleScript, are not only better languages than AppleScript, but are easier than AppleScript, even though neither is very English-like at all.

Amen, brother!

Many months ago I had written “In general, AppleScript code is extremely readable, and relatively close to english.” I do not believe this anymore, and have since revised the article. Too often AppleScript clashes with English syntax. Here are a couple of example AppleScript strings (both from current code v0.26):
@"tell application \"Adium\" to my status type as Unicode text";
@"set volume without output muted"

The first sentence is missing a verb (are we getting or setting?); the second lacks an object (set volume to what?). (It turns out the first gets a string from Adium, describing my status {“offline”, “away”, “available”, etc.}; the second un-mutes sound for the whole system.)

I don’t like the NSAppleScript class because it is extra un-thread-safe. That is to say, you can only use it on from the main thread (hint: performSelectorOnMainThread:). No amount of @synchronized blocks will keep you from crashing (intermittently!) if you use an NSAppleScript anywhere else. There is a workaround that won’t block anything, but the cure is worse then the disease. You can use an NSTask to have the osascript program interpret the script for you. This won’t block anything, but it will be take a long time, and is resource intensive.

Dynamically constructing an NSAppleScript is dangerous. There is no way to pass an array of arguments directly into the script, as can be done with an NSTask. Any quotation marks “” need to be carefully escaped. For example, the AppleScript built from [NSString stringWithFormat:@"tell application \"iChat\" to set status message to \"%@\"", message]; will fail spectacularly if message contains quotation marks.

AppleScript is also leaky. This is another reason why you should follow Apple’s advice, and always cache compiled NSAppleScript objects. Not only is it a time-penalty to recompile them; but you will also leak memory every time a new NSAppleScript object is created.

The Script Editor application sucks. Compared to any modern IDE it’s a bad joke. It’s not just that it’s underpowered — it’s that it’s obviously lacking polish. Error messages are often ungrammatical. A dead giveaway of poor design. (Although I get a perverse laugh out of “Syntax Error \ User canceled.”)

Script Editor won’t let you save or open code that won’t compile! This is a dangerous and serious bug. A user should always be able to save their data at any time. It turns out that Script Editor actually saves source code as a compiled script! So if your code can’t compile right now you can’t save it! I’ve essentially lost a script I wrote for the obsolete Fire IM client, because I can’t even read it without the program being present on my system, since AppleScript can’t “compile” it without finding the program.

Which hilights another problem with Script Editor — it likes to change your code; even if it means breaking it on other computers. If I type POSIX file "/Users/", it is automatically replaced by file "Macintosh HD:Users" when the script is compiled and saved. This is wrong. POSIX file "/Users/" is portable across any MacOSX computer that has the /Users/ directory — which is every desktop computer. But file "Macintosh HD:Users" relies on the computer having it’s root-directory reside on a disk named “Macintosh HD” — and this isn’t always true. The two statements are equavalent on my computer, but not on every computer — Script Editor is in error for forcing the change.

AppleScript comment syntax is broken:
(* this is a block comment in AppleScript*)
— and this is an inline comment
(* this comment should be valid — but it’s not because of the dash, and it will keep your script from running *)

In Objective-C mixing inline and block comments is permitted, /* this comment ... //won't break anything */ Even if no programming language allowed inline comment headers inside a block comment, AppleScript would still suck for doing this. That’s because unlike “//”, “–” is an actual punctuation mark. You can expect to find it inside a comment. (NOTE: “–” should be two single-dash characters, not the long-dash it was turned into. Unfortunately my blogging software always “upgrades” ASCII equivalents of punctuation marks.)

Paths in AppleScript are incompatible with everything else, and hard to work with. AppleScript uses pre-MacOSX style “:”-delimited paths. But every other popular programming language I know of does not not, and nether do any command-line utilities, or any shell I’m aware of. That makes using a command-line utility — which should be a simple task in any scripting language — a chore in AppleScript. For example, let’s say I was using perl, and I had a variable $src that held the path to some file. I could write:
`ditto -ckX --rsrc $src $src.zip`
to create a zip-file of it that preserved all its special MacOSX filesystem settings. $src could have been defined as “~/file”, or it could have come from another command-line utility, etc.

But in AppleScript I would have to write:
do shell script "ditto -ckX --rsrc " & POSIX path of src & " " & POSIX path of src & ".zip"
All the extra ‘<POSIX path of‘ nonsense makes for some unwieldy code. Worse yet AppleScripts’s support of POSIX path’s is deeply flawed. It won’t support ~ expansion. POSIX path of "~/file" resolves to file ":~:file", not file "Macintosh HD:Users:user:file" as it should. So all POSIX paths pased to an AppleScript have to be absolute.

What’s particularly funny about this, is that dragging a file into Script Editor inserts the poorly supported POSIX path to the file into the editor. This is another example of how poorly-designed Apple’s AppleScript IDE is.

AppleScript has no built-in regular expression support. As far as I know it’s the only modern scripting language without regex support. To use a regex in AppleScript, you have to invoke a command-line utility to do it for you, using the do shell script "" command. This introduces a level of “-escaping hell. It’s also very slow. Regex (un)support alone is plenty of reason to use anything but AppleScript for writing scripts.

The concept of libraries in AppleScript is deeply broken at the design level. Because AppleScript is such a minimal language, almost everything is done by asking other programs to do something. in AppleScript, functionality does not come from nested Libraries, but from “Scripting Additions” provided by other applications. This means there isn’t a logical and powerful library hierarchy that makes things easier. Instead you get an irrational flat list of modules, including every application on the system that is scriptable:
AppleScript Library Madness
It’s not always clear who you should “tell” to give you what you need. tell application "Finder" to get every application process gives a list of every running process. But why are we asking the Finder to give us that? The Finder is a file browser, and the “face” of the computer. If I wanted to see this list, I would launch Activity Monitor, or “top”, not mess around in the Finder. Functionality is not logically organized in AppleScript, and this makes writing code hard, because it’s difficult to find what you need.

AppleScript uses an application’s name to identify an application; unfortunately application names are a complex mess on MacOSX.

…there are at least five application names floating around, at least in concept: (1) the file name the Finder sees, which in the case of an application package is the package (bundle) name; (2) the name of the executable inside the package, (3) the long name used in many places for display purposes only; (4) the short name used as the application menu title and in a few other places where a long name won’t fit for display purposes; and (5) the process name of a running application. They aren’t always the same…

–From a message by Bill Cheeseman.

I still like the idea of directly embeding snippets of a scripting language into directly into Cocoa code. That’s a very powerful idea. But I do not like the leaky, and decidedly un-threadsafe implementation of NSAppleScript. I also dislike the AppleScript language and the AppleScript “IDE”. If AppleScript wasn’t currently the best way to script most Mac applications I wouldn’t use it.

Further Reading:
AppleScript likes to mess with your code
Computer Languages aren’t Human Languages

Changing a favicon.ico

September 23, 2007

Changing the favicon.ico for the IMLocation website was more trouble then I expected. Here’s how I finally got it working.

The first problem is making the file. GraphicConverter was doing an unacceptably poor job scaling my 128×128 icon down to 16×16. (PhotoShop can probably generate a favicon.ico like this, with little trouble, but I don’t have it.). I did have luck with this website; upload a {*.gif, *.jpg, *.png, *.ico, *.bmp} and it spits out a favicon.ico in a few sizes.

The second problem was that Safari kept showing the old icon. Emptying the cache, and restarting had no effect. Trashing ~/Library/Safari/Icons/, and restarting Safari worked for me. Unfortunately, anybody who has viewed the old website in Safari will probably keep seeing the old favicon.ico unless they trash their icon database as well. So the first favicon.ico a Safari user sees for your website will probably be the only one they ever see for it.

Error Message Rogues Gallery

September 21, 2007

Here’s a rogues gallery of terrible error messages I’ve encountered personally; along with what the programmers and designers should do to fix them.

I’ve been saving this screenshot for years (To be exact, since January 10, 2000):
An unexpected error occurred, because it cannot be found.

An unexpected error occurred, because it cannot be found.
[OK]

Seriously, WTF? This is one of the best (worst?) examples of bad copy I’ve ever run across. It is perplexing, it is uninformative, and it’s longer then it needs to be — unless there are other kinds of errors then “unexpected” ones.

It is how Mac OS 9 would complain if you tried to open an alias that pointed to a file that could not be found.

Fortunately, it has been fixed. As of Mac OS X 10.4, you get this nice dialog:
Alias Not Found Dialog (Mac OS X 10.4)
Not only does the new dialog clearly explains what’s wrong; it lets you do something about it.

====
This error message is at least lucid, but it drives me mad. It happens any time you try to install an iTunes update with Apple’s Software Update program, and iTunes is running.
quittocontinue.png

iTunes
Please quit iTunes before continuing with this update.
[Continue]

Two things are wrong here. First there is no way to cancel or defer the installation. Click “Continue”, and you are bludgened again and again with this message until you submit. Very unfriendly.

Secondly, the installer can and should do this for you. Instead of reading “Continue”, the button should read “Quit iTunes”, and hitting it should tell iTunes to quit. Asking programs to quit is a solved problem. It has been a solved problem for decades. It happens every single time every single Mac is shut down.

Dialogs should never force the user to do work that the program can do.

====
I use SBC DSL at my apartment. When it has problems, which it frequently does, it takes you to a webpage that displays an error message. So far so good. But when everything starts working again, it hijacks the next URL you try to load and takes you to this error message instead (note that hitting back or reload won’t give you the webpage you were trying to get to):
SBC Sucks
Everything is fine.  I’m sure you wanted to see this message instead of the page you were trying to load.

(*SBC logo*) Gateway Alert Notification
(*Error Logo*) Success
Resolution Successful
The error has been successfully resolved. Please close down your browser and restart it to continue browsing online.

(If you have the same router I do, you can see the error message here).
Lot’s of problems I’ll address them in order of severity.

Despite what the message says, you do not need to restart anything. The next page you load will get to you just fine. This is a horrible legal-department-inspired cop-out that ends up giving bad advice. Error messages should never give incorrect advice. It’s better have an uninformative message, then to tell the user to do something wrong, which will compound their problems ( that leads to disaster.)

Displaying this message eats the URL you were trying to load, and there is no way to get it back. “Reload” just reloads the static message.

This error message should not exist in the first place. If things are working, then you get the URL you ask for. Otherwise, you get an error message. There is no need to indicate things are back to normal, the fact that things are working normally indicates it just fine. Alerts are for exceptional situations, not routine or normal ones.

The message looks too scary. It is informing the user that everything is working, so it should not have the same harsh red coloring, and warning-sign icons as the “YOUR INTERNET IS BROKEN!” messages have. Even though this particular message should not exist, “Informational Alerts” are a valid dialog to show the user. The same loud shapes and colors used to announce a catastrophic error should not be used to announce that updates are ready.

The design sucks, and so does the copy. The simple message uses a staggering three headlines and two icons. It took a while for the enormity of that to hit me. Ether one of the bottom two headlines would have worked just fine.
The topmost headline is terrible. The word “Gateway” is technical jargon. “Alert Notification” is amateur copy — an alert is a notification and vica versa — ether word would work on it’s own, together they trip over each-other. “SBC Internet Service Alert” would be acceptable.
The rest of the copy is overly verbose, and ‘fair’ at best.

Finally none of the SBC error messages list the support number to call if something is broken at their end (which has happened). I suspect this is a chicken-shit move designed to drive down call-center costs by discouraging callers. Regardless of the cause, the effect is that all their error messages, including this one, are lacking critical information that would help a resolution.

The solution to all these problems is to omit “everything is working” messages. Let the program’s functionality, or the lack of messages indicate it.

foreach Macro

September 20, 2007

This article has been updated, and moved here.

Use Amazon to Search Your Books

September 13, 2007

I have started using Amazon.com to search books I own for a particular passage. It’s infinitely easier then linearly scanning through the book. It even beats out the book’s own index. Both in ease of use and completeness.

Google Books, and to a lesser extent Google Scholar have worked for me as well, but so far I have had an easier time finding a book, and searching inside it, with Amazon.

After reading an undisclosed number of pages of a book online, Amazon won’t let you see any more excerpts. So if a search result looks promising, I look it up in the book, rather then click the link, just in case. Google Books may well have a similar restriction. I don’t know, I don’t use it as much.

For ingesting a large chunk of information, books are still king. But for searching they’re pretty bad.

Strange Objects (NSCFType, etc.) Indicate Memory Management Bugs.

September 13, 2007

Any errors involving NSCFType or some class you have never heard of (eg ” *** -[NSCFType count]: selector not recognized “) are indicators of a memory management bug. Most likely an object is getting released too soon. The freed memory is then re-allocated for a new object, say an NSCFType. The pointer to the over-released object, obj, has not changed, but is now pointing to a NSCFType, which receives any messages sent to obj (and chokes on most of them).

NSCFType is not documented anywhere by Apple. As near as I can tell, it’s some deep-dark part of Core Foundation, but whatever it really is, it’s clearly not meant to venture out of it’s deep-dark lair. So seeing it means something is very wrong.

Any “selector not recognized” message may also be the result of an early-release. I have had cases where over-released memory was reallocated as an NSString, or other ubiquitous class. However, the vast majority of my “selector not recognized” issues were caused by explicitly sending the wrong message to an object (invoking count on an NSString for example).

EDITED TO ADD: In addition to NSCFType I have also seen memory bee recycled as NSExtraMIData.