Thursday, March 12, 2015

Try

Neven Mrgan:

OneShot tried, and shaved off some work from this task, and that’s helpful enough. If it got it wrong, oh well, no harm done. My instinct says Apple wouldn’t ship a feature like this—they’d want it to work 100% of the time, or not at all.

I’d like to see more software try to do a good job of a fuzzy task, let you help it with the last mile, and give you a fallback option. That kind of magic can be more delightful than behind-the-scenes, guess-and-stick-with-it magic we’re often promised.

7 Comments RSS · Twitter

He's right about Apple. Apple didn't even include exception handling in its new language Swift. According to Apple, don't try anything unless you are 100% sure of success. If you fail anyway, take the low-level reason for the failure and pass it back up the stack until it has lost all context.

But that Apple's advice for 3rd party developers. Apple's own code is written by Apple and can therefore never fail. That is why Cocoa is not exception-safe.

@John Daniel: I'm pretty sure Swift's lack of exception handing has more to do with the nature of ObjC and Cocoa, which were never designed to handle exceptions. Exceptions crash through the stack hard, making them an absolute nightmare to clean up behind without any automatic memory/resource management. Given ObjC memory management was traditionally semi-manual, it made sense for Cocoa to use (albeit inconsistently) a different error reporting scheme: returning nil to indicate failure and NSError** to supply additional error info as needed.

In fact, returning error values is a perfectly good way to do it, as long as the language provides expressive features such as sum types and pattern matching that avoid the need for vast swathes of boilerplate regardless of whether you wish to handle errors or not. Obviously, there's been problems: Swift as released was from fully-baked and its sum type support was borked, plus it's going to take a long time to rework existing Cocoa APIs and coders' existing habits.

Personally, what I'd really like to see from the Swift devs is a best-of-both-worlds solution that allows coders to choose whether they want to handle an NSError result or explicitly ignore it. If the latter, the compiler should just inject some default error handling logic that raises the error to a permanent exception.

Such behavior would be extremely useful during early development, when your main concern is exploring and understanding the problem space, not dotting and crossing every single "i" and "t" just to make every bit of experimental, unfinished, or throwaway code compile before you can see how it runs.

Mind you, even production apps should find such a mechanism useful, as there may be plenty of error conditions that the author overlooked, or considered too rare to worry about, or too unrecoverable to do anything about. In which case dumping an exception right down to the main loop ensures that both developer and user know a problem has occurred, and it's probably a good time to save all current data and restart the app before going any further. Certainly better than traditional ObjC/Cocoa, where the tendency is to return a nil that gets invisibly swallowed by the messaging system, so that nobody knows if, where, or when such insouciance might blow back next.

...

(Actually, what'd be really awesome would be if the compiler could return an Error without actually unwinding the stack, allowing the caller the opportunity to correct the problem and then return control to where it left off. But I guess we'll have to wait another generation for the rest of the programming world to reinvent solutions to problems that the Lisp world already solved decades ago.:p)

@mjtsai: You have to remember, Apple is a brand first, a product second, and a technology last. Computer geeks always get that order backwards, because they've a hard time grasping that others' priorities are different to their own.

Humans, they are a difficult concept.

In fact, Apple were pretty much first to introduce the ability for ordinary users to try stuff and then backtrack if they didn't like the result with Edit>Undo. But there's a difference between Apple allowing the user to make their own mistake, and making those mistakes for them.

I quite agree that automating the process of making of mistakes - thus saving users having to make those mistakes manually - is a useful tool to have. But I'd also guarantee that if Apple were to implement such a feature they'd be utterly massacred by swathes of users outraged that their machines are now "broken" because they're "doing stuff wrong".

To illustrate, look no further than Exhibit A in "1000 Reasons Why We Can't Have Nice Things". Reading that, you can hardly blame Apple for not wishing to call down a further 999 worlds of hurt upon itself.

@has,
Yes. I've heard all of that revisionist rationalization before. But you've got it backwards. ARC is one of the justifications that Apple uses to denigrate exceptions. The truth is, while one team at Apple was building, and enhancing, Objective-C's exception handling mechanism another team was ignoring it. The other team, the Cocoa team, eventually won their internal debate and banished exceptions altogether. That seems to have happened around 2010 when Apple slipped one line into the exception-handling documentation saying that we shouldn't have been using it for the past ten years. Then there was that 3rd team using exceptions for normal flow-control.

I know Swift is the darling among the younger crowd. I'll use it too for UI work. But for my own business logic, I'm kicking Apple technology to the curb and using more mainstream methods like C++ and exceptions.

I don’t understand how we’re supposed to use Swift when (a) Apple’s frameworks raise exceptions and (b) Swift dies when it encounters an exception.

"My instinct says Apple wouldn’t ship a feature like this—they’d want it to work 100% of the time, or not at all."

Junk Mail in Apple Mail, Faces in iPhotos, Siri in iOS, Dictation on OS X, Places search in Maps?

"I don’t understand how we’re supposed to use Swift when (a) Apple’s frameworks raise exceptions and (b) Swift dies when it encounters an exception."
You just have to avoid those operations that are known to cause exceptions and/or verify, ahead of time, that the operation will not fail. The former means never, ever use NSFileHandle in Swift. The latter means breaking old anti-race-condition habits of trying and handling failures. We literally have to check first and then assume failure is impossible. A 3rd option is a Swift wrapper around try/catch implemented in Objective-C.

A bigger question is how all of this gets documented. I never knew about the exception problems in Cocoa until Swift came out. It was only mentioned in literally one line of the exception handling documentation. I was a big fan of exceptions in C++. So when I originally read the exception handling documentation, and later learned about Objective-C's improved exception handling for 64-bit, I saw no reason not to use them. I obviously never noticed when that one line was added in 2010. Apparently it was widely known before then, but not by me.

It took some effort by an Apple engineer in the developer forums to make me understand what "not exception-safe" meant. To say something is "not thread-safe" means you need a little extra work for thread safety. But "not exception-safe" means you just can't use them at all. Apparently this is how Apple documentation works now. You just have to make sure you are "in the know", troll developer forums and spout off about things you don't fully understand in hopes of being corrected, read header files, and only look at official documentation as a last resort because it may be ten years out of date, flat-out wrong, or even misleading due to internal Apple politics.

The best methods right now are header files and experimentation. There are many methods that aren't mentioned anywhere except header files. It is only through experimentation that you would learn that IKImageKit is fundamentally broken, NSImageView isn't much better, and NSFileCoordination only supports about 20% of is documented methods.

Leave a Comment