Uncaught exceptions thrown by Cocoa documented anywhere?

  • Are uncaught exceptions that are thrown by Cocoa documented anywhere?

    [NSURL fileURLWithPath:nil]; throws an uncaught exception.

    NSPersistentStoreCoordinator's addPersistentStoreWithType:
    configuration: URL: options: error: throws an uncaught exception when
    URL is nil.

    I discovered these by removing my Core Data SQLite store from the
    resource folder of my app's bundle, launching the app, and watching
    it crash.

    I have now fixed my app to gracefully continue in a crippled state
    without the store, instead of crashing.

    I imagine I'm not the only one who would like to know when Cocoa
    throws an uncaught exception.  Are they documented anywhere?

    Thanks,
    James
  • On Feb 13, 2008, at 2:27 PM, James Hober wrote:
    > I imagine I'm not the only one who would like to know when Cocoa
    > throws an uncaught exception.  Are they documented anywhere?

    Not consistently.  Some methods are documented as throwing exceptions,
    and others aren't.  Similarly, some method documentation specifies
    what the error return value would be, and others don't specify
    anything about error handling.

    I find Apple's documentation particularly bad in this regard, compared
    to say the documentation for the Java, Python, C, or C++ standard
    libraries, and other proprietary libraries like MFC or QT.  Overall I
    think Cocoa is impressive, but the documentation leaves a lot to be
    desired, at least as far as being consistent and well organized.
  • On Feb 13, 2008, at 11:49 AM, Adam P Jenkins wrote:
    >
    > On Feb 13, 2008, at 2:27 PM, James Hober wrote:
    >> I imagine I'm not the only one who would like to know when Cocoa
    >> throws an uncaught exception.  Are they documented anywhere?
    >
    > Not consistently.  Some methods are documented as throwing exceptions,
    > and others aren't.  Similarly, some method documentation specifies
    > what the error return value would be, and others don't specify
    > anything about error handling.
    >
    > I find Apple's documentation particularly bad in this regard, compared
    > to say the documentation for the Java, Python, C, or C++ standard
    > libraries, and other proprietary libraries like MFC or QT.  Overall I
    > think Cocoa is impressive, but the documentation leaves a lot to be
    > desired, at least as far as being consistent and well organized.

    Well, I did the feedback at the bottom of the documentation pages.  I
    asked for the two exceptions I encountered to be documented.  And I
    asked for uncaught exceptions that Cocoa throws to be documented in
    general.

    I mostly like Apple's documentation.  Although one other thing snares
    me: Sometimes I just want to know the simple way to do something.
    Other times I want technical details.  It would be nice if these
    could be separated a little better.

    James
  • On 13 Feb '08, at 11:43 AM, Adam P Jenkins wrote:

    > Not consistently.  Some methods are documented as throwing
    > exceptions, and others aren't.

    In general, IIRC, you can mostly assume that unless a object parameter
    is explicitly documented as accepting nil as a legal value, it doesn't
    allow nil. The docs also aren't generally going to talk about what
    exceptions are raised, rather about what things are valid or invalid.

    > I find Apple's documentation particularly bad in this regard,
    > compared to say the documentation for the Java, Python, C, or C++
    > standard libraries, and other proprietary libraries like MFC or QT.

    Cocoa's philosophy on exceptions is different than those. In most
    languages that have exceptions, exceptions are considered things that
    can legally happen in uncommon but valid situations: 'file not found',
    'can't parse this string into a number', etc. So the exceptions a
    method can throw are part of its API, since exceptions are an
    alternate return value.

    But the Cocoa architects basically dislike exceptions, and the Cocoa
    frameworks (with a very few exceptions) raise exceptions only to
    indicate *programmer errors*: passing an illegal value to a parameter,
    accessing an invalid array index, calling a nonexistent method, etc.
    (It's roughly like the distinction between checked and unchecked
    exceptions in Java.) So exceptions aren't part of the API, they're
    just a mechanism for code to bail out if something illegal happens.

    I don't happen to agree with this philosophy (and have been involved
    in too many internal debates about it...) but that's the way it is.

    —Jens
  • On 14/02/2008, at 10:48 AM, Jens Alfke wrote:

    > But the Cocoa architects basically dislike exceptions, and the Cocoa
    > frameworks (with a very few exceptions) raise exceptions only to
    > indicate *programmer errors*: passing an illegal value to a
    > parameter, accessing an invalid array index, calling a nonexistent
    > method, etc. (It's roughly like the distinction between checked and
    > unchecked exceptions in Java.) So exceptions aren't part of the API,
    > they're just a mechanism for code to bail out if something illegal
    > happens.

    There's one exception that comes to mind that's bitten me a few times:
    NSFileHandle. It throws an exception whenever there's a problem and
    what's worse (IIRC) is that it doesn't give you an error code—just an
    error string. I now use a category method of my own:
    availableDataOrError: instead of the availableData method.

    > I don't happen to agree with this philosophy (and have been involved
    > in too many internal debates about it...) but that's the way it is.

    At the risk of sparking debate, I definitely prefer the philosophy
    that Cocoa tends to use. It's too easy to forget to handle exceptions
    whereas you're forced to handle an error condition if something
    explicitly returns an indication. If you want exceptions to be thrown
    you can easily wrap the code to do that. (You can of course wrap code
    that throws exceptions to return errors instead, but I think this is
    more unpleasant than the other way round.) Part of my attitude on this
    comes from C++ where I think it's difficult to make code exception safe.

    - Chris
  • On 13 Feb '08, at 4:10 PM, Chris Suter wrote:

    > At the risk of sparking debate,

    Must ... avoid ... replying ...
    Willpower ... draining ...
    "Reply" button ... growing ... looming ... throbbing ... AUUUGH!

    > I definitely prefer the philosophy that Cocoa tends to use. It's too
    > easy to forget to handle exceptions whereas you're forced to handle
    > an error condition if something explicitly returns an indication.

    I find it's the other way around: you can ignore errors when they're
    just numbers being returned by a function. All you do is forget to
    assign the return value to a variable, or check that variable.
    (Especially since the world is full of sample code that does exactly
    that.) But you can't ignore an exception without explicitly wrapping
    an empty try/catch block around it.

    Moreover, exceptions are more consistent than code that sometimes
    returns a boolean, sometimes an error number, sometimes an 'out'
    struct. And if you want to set a breakpoint when an error occurs (an
    extremely useful debugging technique) it's easy to do with exceptions,
    much harder with error codes unless you wrap every function in some
    kind of "checkError( )" call.

    If nothing else, I think the fact that every other major OOP language/
    framework uses thrown exceptions is pretty significant. Cocoa's
    philosophy is, I think, a holdover from the early days of NeXT before
    there were exceptions; changing the APIs to use them in a meaningful
    way would have been too difficult, especially for developers rewriting
    their apps, so they adopted them only to the extent of using them as a
    recoverable assertion mechanism.

    OK, that's all. (That nice Dr. Zimmerman would like me to tell
    everyone that the Shady Dell Sanatorium will not be passing any
    replies on to me, for the duration of my rehabilitation program.
    Thanks for your support.)

    —Jens
  • On Feb 13, 2008, at 3:48 PM, Jens Alfke wrote:
    > But the Cocoa architects basically dislike exceptions, and the Cocoa
    > frameworks (with a very few exceptions) raise exceptions only to
    > indicate *programmer errors*: passing an illegal value to a
    > parameter, accessing an invalid array index, calling a nonexistent
    > method, etc. (It's roughly like the distinction between checked and
    > unchecked exceptions in Java.) So exceptions aren't part of the API,
    > they're just a mechanism for code to bail out if something illegal
    > happens.
    >
    > I don't happen to agree with this philosophy (and have been involved
    > in too many internal debates about it...) but that's the way it is.

    Two additional points -- neither of which are intended to express my
    particular philosophy or opinion regarding exception handling:

    (1) In the 32 bit [Legacy] Objective-C ABI, creating an exception
    handler is very expensive;  CPU cycles and chunks of memory are
    consumed.  Thus, having loads of exception handlers floating around
    your code in the Java-esque style of exceptions-as-error-execution-
    path can incur a measurable and noticeable performance impact.

    (2) That Cocoa is implemented with the philosophy as described by Jens
    means that you will generally benefit -- your code will generally be
    simpler, easier to maintain, and work better across versions of the
    system -- if you follow the same implementation pattern, regardless of
    personal beliefs.

    If you do decide to go the java-esque route of using exceptions to
    encapsulate and perpetuate user level erroneous conditions, make
    damned sure you do not toss exceptions through frames contained with
    Cocoa.

    b.bum
  • On Feb 13, 2008, at 4:13 PM, Jens Alfke wrote:

    > But the Cocoa architects basically dislike exceptions, and the Cocoa
    > frameworks (with a very few exceptions) raise exceptions only to
    > indicate *programmer errors*: passing an illegal value to a parameter,
    > accessing an invalid array index, calling a nonexistent method, etc.

    This is fine when it bites you immediately.  But what if I write:

    NSString *filePath = [[NSBundle mainBundle]
    pathForResource:@"MyTextFile" ofType:@"txt"];

    NSURL *url = [NSURL fileURLWithPath:filePath];

    Is this programmer error?

    It is programmer error!  But it will compile fine, run fine and never
    throw an exception UNLESS I remove MyTextFile.txt from the app's
    package.  In that case, filePath will be nil and fileURLWithPath will
    throw.

    Instinctively I would check that url != nil before using it.  But to
    code correctly I have to check that filePath != nil or wrap the
    second statement in a try block.  I cannot know to do this unless I
    know that fileURLWithPath can throw.

    How can I know that a method like fileURLWithPath, which already can
    return nil for errors, might throw an exception?
    1. I can chance upon the trigger.
    2. I can realize, now that you have told us, that generally a
    parameter cannot be nil unless the docs say it can. (And of course,
    many parameters can be nil!)
    3. I can read that it throws an exception in the documentation,
    assuming the documentation says so.  And we began this discussion
    lamenting it doesn't always.

    James
  • On Feb 13, 2008, at 11:05 PM, Bill Bumgarner wrote:

    > Two additional points -- neither of which are intended to express my
    > particular philosophy or opinion regarding exception handling:
    >
    > [...]
    > (2) That Cocoa is implemented with the philosophy as described by
    > Jens means that you will generally benefit -- your code will
    > generally be simpler, easier to maintain, and work better across
    > versions of the system -- if you follow the same implementation
    > pattern, regardless of personal beliefs.
    >
    > If you do decide to go the java-esque route of using exceptions to
    > encapsulate and perpetuate user level erroneous conditions, make
    > damned sure you do not toss exceptions through frames contained with
    > Cocoa.

    What if you're using GC (and wrapping non-Cocoa things with
    *MakeCollectable())--is it then safe to use exceptions through Cocoa
    frames?

    Cheers!
    --Chris Ryland / Em Software, Inc. / www.emsoftware.com
  • On Feb 15, 2008, at 8:49 AM, Chris Ryland wrote:
    > What if you're using GC (and wrapping non-Cocoa things with
    > *MakeCollectable())--is it then safe to use exceptions through Cocoa
    > frames?

    No;  it isn't limited to memory management issues.  There may be any
    number of bits of teardown / cleanup code that will be skipped as the
    exception passes over it.

    b.bum
  • Bill Bumgarner wrote:
    > On Feb 15, 2008, at 8:49 AM, Chris Ryland wrote:
    >> What if you're using GC (and wrapping non-Cocoa things with
    >> *MakeCollectable())--is it then safe to use exceptions through Cocoa
    >> frames?
    >
    > No;  it isn't limited to memory management issues.  There may be any
    > number of bits of teardown / cleanup code that will be skipped as the
    > exception passes over it.
    That's always been my problem with exception handling in general. When
    everything is working fine, it's great and makes code look simpler. When
    a problem actually occurs, I think understanding the flow of control is
    extremely difficult if you aren't intimately familiar with the code base.

    Unless you are extremely diligent, exceptions can leave your app in a
    weird state, with partially-completed things laying around. I know there
    are plenty of patterns and techniques for "doing things right," but I
    work in a group setting with lots of other developers, and I honestly
    don't think it's reasonable to expect them to get every little detail
    right—there's too many details that you need to know. (A lot of them
    write fairly procedural code to begin with, which is much harder to make
    exception-safe than object-oriented code.) It's not too hard to write
    code that runs from top to bottom and cleans up after itself as it runs,
    but when you consider that, at any point, your code might veer off into
    the weeds and get thrown into a different path of execution, suddenly
    the cleanup process gets a lot trickier.
  • On Friday, February 15, 2008, at 09:18AM, "John Stiles" <JStiles...> wrote:
    > Bill Bumgarner wrote:
    >> On Feb 15, 2008, at 8:49 AM, Chris Ryland wrote:
    >>> What if you're using GC (and wrapping non-Cocoa things with
    >>> *MakeCollectable())--is it then safe to use exceptions through Cocoa
    >>> frames?
    >>
    >> No;  it isn't limited to memory management issues.  There may be any
    >> number of bits of teardown / cleanup code that will be skipped as the
    >> exception passes over it.
    > That's always been my problem with exception handling in general. When
    > everything is working fine, it's great and makes code look simpler. When
    > a problem actually occurs, I think understanding the flow of control is
    > extremely difficult if you aren't intimately familiar with the code base.

    As a concrete example, this bit us when converting an app to use the NSDocument saving methods in 10.4 that use NSError** parameters.  In 10.3 and earlier, we had been throwing exceptions and using them to bubble an informative error back up to the user for a lower-level save problem (string encoding conversion), but exceptions and NSError** do not mix.

    It's really easy to throw an exception that keeps you from initializing an error pointer properly, and when you or AppKit try an use a garbage error, bad things happen...most of the time.  The most stable solution was to eliminate exceptions and use NSErrors; this led to more code (NSErrors are annoyingly messy to create), but with far fewer problems.

    --
    adam
  • On Feb 15, 2008, at 11:55 AM, Bill Bumgarner wrote:

    > On Feb 15, 2008, at 8:49 AM, Chris Ryland wrote:
    >> What if you're using GC (and wrapping non-Cocoa things with
    >> *MakeCollectable())--is it then safe to use exceptions through
    >> Cocoa frames?
    >
    > No;  it isn't limited to memory management issues.  There may be
    > any number of bits of teardown / cleanup code that will be skipped
    > as the exception passes over it.

    What you're saying is that the Cocoa culture doesn't generally use
    @try/finally to wrap teardown/cleanup/finalize code, so it's generally
    not safe to use exceptions for flow control, unlike Python?

    Cheers!
    --Chris Ryland / Em Software, Inc. / www.emsoftware.com
  • On Feb 15, 2008, at 9:50 AM, Chris Ryland wrote:
    > What you're saying is that the Cocoa culture doesn't generally use
    > @try/finally to wrap teardown/cleanup/finalize code, so it's
    > generally not safe to use exceptions for flow control, unlike Python?

    Exactly.

    Cocoa only uses exceptions to indicate programmer ever and not to
    encapsulate user error.

    Exceptions are generally indicative of non-recoverable state;  actual
    bugs in the code or misuse of API.

    b.bum
  • On Feb 15, 2008, at 10:04 AM, Bill Bumgarner wrote:
    > Exactly.
    >
    > Cocoa only uses exceptions to indicate programmer ever and not to
    > encapsulate user error.

    Wow.  Lack o' Coffee.

    Cocoa only uses exceptions to indicate programmer error, not to
    encapsulate user error.

    There are a handful of exceptions (hah!) to this rule.  Unfortunate
    inconsistencies.

    b.bum
  • On Feb 15, 2008, at 12:50 PM, Chris Ryland wrote:
    > What you're saying is that the Cocoa culture doesn't generally use
    > @try/finally to wrap teardown/cleanup/finalize code, so it's
    > generally not safe to use exceptions for flow control, unlike Python?

    Or even for indicating errors it would seem.  Basically if the Cocoa
    code base is not designed to be exception-safe, then you better not
    ever let an exception escape into Cocoa code.  Sounds reasonable.

    I would just point out that this doesn't demonstrate a problem with
    exceptions per-se, any more than the existence of non-thread-safe code
    indicates a problem with using threads.  Writing exception-safe code
    is similar to writing thread-safe code in that it's a lot easier if
    you've considered it throughout the code's lifetime rather than trying
    to introduce it late in the codebase's life.  Given that exceptions
    were only recently added to Objective-C, it's not surprising that most
    existing ObjC code isn't exception-safe.
  • On Feb 15, 2008, at 11:15 AM, Adam P Jenkins wrote:
    > I would just point out that this doesn't demonstrate a problem with
    > exceptions per-se, any more than the existence of non-thread-safe
    > code indicates a problem with using threads.  Writing exception-safe
    > code is similar to writing thread-safe code in that it's a lot
    > easier if you've considered it throughout the code's lifetime rather
    > than trying to introduce it late in the codebase's life.  Given that
    > exceptions were only recently added to Objective-C, it's not
    > surprising that most existing ObjC code isn't exception-safe.

    Exceptions have been in Cocoa since the late '80s...

    @try/@catch/@finally was a relatively recent addition in the last few
    years, but the NS_DURING/NS_HANDLER/NS_ENDHANDLER served that purpose
    prior.

    b.bum
  • On Feb 15, 2008, at 11:32 AM, Bill Bumgarner wrote:

    > On Feb 15, 2008, at 11:15 AM, Adam P Jenkins wrote:
    >> Writing exception-safe code is similar to writing thread-safe code
    >> in that it's a lot easier if you've considered it throughout the
    >> code's lifetime rather than trying to introduce it late in the
    >> codebase's life.  Given that exceptions were only recently added to
    >> Objective-C, it's not surprising that most existing ObjC code isn't
    >> exception-safe.
    >
    > Exceptions have been in Cocoa since the late '80s...
    >
    > @try/@catch/@finally was a relatively recent addition in the last
    > few years, but the NS_DURING/NS_HANDLER/NS_ENDHANDLER served that
    > purpose prior.

    However, when the old-style exception macros were introduced, the
    unfortunate decision to base them on setjmp rather than to extend the
    language to make them zero-overhead-unless-thrown ("zero-cost" in the C
    ++ and Java world) ensured that they weren't very widely used because
    every NS_DURING/NS_HANDLER/NS_ENDHANDLER incurred a significant
    performance penalty and required marking variables as "volatile" for
    correctness etc.

    I think this even more than historical legacy is what prevented
    OpenStep from being exception-safe at its introduction in 1994; after
    all, it had to run reasonably on 25MHz 68040 hardware with 32MB (or
    even less) memory.

    Truly modern language-level exceptions -- which allow variables to be
    marked volatile automatically by the compiler, which allow type-based
    rather than name-based matching of exceptions to handlers, and which
    can have a transparent zero-cost implementation -- really were only
    added to Objective-C in Mac OS X 10.3 in 2003.  And it took until the
    introduction of the 64-bit Objective-C runtime to actually ship zero-
    cost exceptions.

    Alas, all this is despite exceptions being an established best
    practice for safe error propagation and recovery since the mid-1970s
    in academia (aka Lisp, Ada and functional languages), and since the
    early 1990s in the C++ community (and subsequently in the Java
    and .NET communities).

    Which is really too bad, because pervasive exception-safe code makes
    it very easy to cleanly propagate errors across layers of a system to
    the point at which it's appropriate to handle them.  Instead right
    now, if something deep inside your code can return an NSError,
    everything between the call that can return the error and your UI
    needs to be able to propagate it out.  It's the bad old days of OSErr
    or HRESULT propagation all over again, where every call has to be
    wrapped in an "if" block and every method has to return a result code
    that the next layer checks.

      -- Chris
  • On Feb 15, 2008, at 7:58 PM, Chris Hanson wrote:
    > I think this even more than historical legacy is what prevented
    > OpenStep from being exception-safe at its introduction in 1994;
    > after all, it had to run reasonably on 25MHz 68040 hardware with
    > 32MB (or even less) memory.

    That would be an incorrect assumption.

    OpenStep was not "exception-safe" as a conscious design decision.  The
    designers of the API decided precisely that exceptions would only be
    used to encapsulate and indicate non-recoverable, programmer, type
    errors.

    If the decision had been made to use exceptions as a means of
    encapsulating recoverable, user level, errors, then the performance
    issues of exception handling would have been addressed in the compiler
    and runtime.

    Yes, I asked someone involved in the design of OpenStep.

    b.bum
  • On 16.02.2008, at 04:58, Chris Hanson wrote:

    > I think this even more than historical legacy is what prevented
    > OpenStep from being exception-safe at its introduction in 1994;
    > after all, it had to run reasonably on 25MHz 68040 hardware with
    > 32MB (or even less) memory.

    I´m not sure which CodeWarrior DR variant finally implemented C++
    exceptions (DR1 was released in 1/1994), but probably since then the
    zero cost handlers were AFAIR state of the art on 68k systems (my copy
    of CW ran on a 68030 Powerbook 140)..

    > Alas, all this is despite exceptions being an established best
    > practice for safe error propagation and recovery since the mid-1970s
    > in academia (aka Lisp, Ada and functional languages), and since the
    > early 1990s in the C++ community [...]

    .. Thanks to some outstanding C++ advocates educating developers how
    to write really working "rollback" code ;-), basically by splitting
    code into atomic units that might succeed or fail ...

    > Which is really too bad, because pervasive exception-safe code makes
    > it very easy to cleanly propagate errors across layers of a system
    > to the point at which it's appropriate to handle them.  Instead
    > right now, if something deep inside your code can return an NSError,
    > everything between the call that can return the error and your UI
    > needs to be able to propagate it out.  It's the bad old days of
    > OSErr or HRESULT propagation all over again, where every call has to
    > be wrapped in an "if" block and every method has to return a result
    > code that the next layer checks.

    I still consider it worse - most of Foundation et al is not
    retrofitted to error handling but returns nil and there is no way to
    tell the user WHY he really lost data. And most of the existing code
    I've seen is written with then same "return nil on error" paradigm in
    mind, so there is also no up-propagation of an error state...

    Regards,
    Tom_E
  • On Feb 15, 2008, at 8:42 PM, Bill Bumgarner wrote:

    > On Feb 15, 2008, at 7:58 PM, Chris Hanson wrote:
    >> I think this even more than historical legacy is what prevented
    >> OpenStep from being exception-safe at its introduction in 1994;
    >> after all, it had to run reasonably on 25MHz 68040 hardware with
    >> 32MB (or even less) memory.
    >
    > That would be an incorrect assumption.
    >
    > OpenStep was not "exception-safe" as a conscious design decision.
    > The designers of the API decided precisely that exceptions would
    > only be used to encapsulate and indicate non-recoverable,
    > programmer, type errors.
    >
    > If the decision had been made to use exceptions as a means of
    > encapsulating recoverable, user level, errors, then the performance
    > issues of exception handling would have been addressed in the
    > compiler and runtime.

    That's extremely unfortunate; it means that OpenStep's lack of
    exception safety is *not* just an engineering trade-off, but instead
    represents a serious design flaw.

    At least such things are rare.

      -- Chris
  • On Feb 16, 2008, at 1:23 AM, Chris Hanson wrote:
    > That's extremely unfortunate; it means that OpenStep's lack of
    > exception safety is *not* just an engineering trade-off, but instead
    > represents a serious design flaw.

    Please stop mixing fact and opinion.

    There are those -- some very very really terribly smart -- people who
    feel that it is a design feature.  Thus indicating that one camp is
    either incorrect or, more likely, there is a huge wash of nearly
    religious grey areas in between.

    This is not the forum to argue the philosophy of design of something
    that will not change.

    (If anyone is keeping score, I have tried to be careful to *not*
    express an opinion on this one.  I have one and it has changed
    radically over the years.  Twice, no less.  But that is OT for cocoa-
    dev.)

    b.bum