Should error reporting bind *print-circle* to T? - error-handling

When CL reports an error, it often prints objects which caused the error.
Should CL bind *print-circle* (or *print-length*/*print-level*) when printing errors?
The ANSI CL Standard seems to be silent on the issue.
Pro: Stack overflow errors like Clisp "Program stack overflow. RESET" on a (cadr). How? are avoided.
Con: ordinary error messages can become
too cluttered and, thus, less comprehensible to novice users (this is why *print-circle* defaults to nil) or
too brief and, thus, less comprehensible (this is why *print-level* and *print-length* default to nil)
This seems to be an example of a "Low-Probability High-Consequence" situation: circular structures are relatively rare, but inability to print them in error messages is devastating to an unsuspecting user.
SBCL seems to do that (in fact, it prints the offending object twice, once with *print-length*/*print-level* and once with *print-circle*).
CLISP does not.

That's left to the implementation and or the development environment.
Note that we are talking about printing errors, not the value of *print-circle* in a debugger.
Clozure CL for example has the variable *ERROR-PRINT-CIRCLE*, which provides the corresponding value for *print-circle* when printing errors.
Similar CCL has values for *error-print-level* and *error-print-length*.

Related

How can I trace a variable which causes an exception with Xcode?

My program crashes after indicating the following. I know something bad occured with the NSArrays. How should I trace the array variable which causes the exception?
Tracing the array isn't going to help you here that much (but see below). You've overreleased something, probably the NSArray itself, and you're not finding out about it until the autorelease pool drains. These can be some of the hardest bugs to track down; hopefully it reproduces consistently.
The typical solutions are:
Make sure you're using ARC. This is precisely the kind of bug that ARC does an excellent job of avoiding. (And usually this kind of crash suggests you're not using it; but it is possible to get them under ARC in some cases.)
Work out which NSArray is having trouble. Audit its usage and make sure that (if you're not using ARC), you are following the memory management rules at each point. Regarding "work out which NSArray," this can be tricky in itself, but some common sense often is the best tool here. You probably have some sense of what object it is. A little trial and error can go a long way.
Avoid direct ivar access; always use accessors except in init and dealloc. This is the best way (besides ARC) to avoid these kinds of memory errors.
Instruments can add traces on retains and releases (use the Zombies instrument). And there is NSZombies, which can help as well. But I have found in the vast majority of cases, the best first step is to search for all the times you use the object, and then check your retains and releases by hand. (I'm not saying any of these approaches is easy; just that a quick by-hand audit is often more effective than the tools.)
And of course make sure to use ARC.
The BEST way to do this, which will help you on MANY occasions, is to set up XCode to automatically break when exceptions are thrown where they are thrown. You can do this as follows:
STEP 1: Go to the breakpoints navigator.
STEP 2: Go to the bottom left and hit '+' and add exception breakpoint.
STEP 3: Find the breakpoint you just added above, right-click, and edit.
STEP 4: Change it to break on all Objective-C exceptions, and the vast majority of crashes will break where the crash occurred.
When the exception occurs, you can act as if you're normally debugging - print values to the console, or hover over them to see what their values are.

Using exceptions in Objective-C

I'm new to Objective-C world. What I have noticed while studying some iOS/Mac apps is that try -catch is rarely used, if used at all.
For example in Java it is used almost all the time.
Why isn't it so common in Objective-C ?
Exceptions in Objective-C are generally to be used for truly exceptional circumstances and almost always programmer error. To convey a recoverable error use the NSError** pattern.
There are a lot of SDK methods that take an NSError** parameter and return BOOL. To indicate an error they return false and feed an error back through the error parameter to communicate info.
Exceptions are used, but generally for cases in which there is some failure at the runtime level - e.g. some object can't handle a selector. Although it may seem contrary to what I just wrote, exceptions tend to indicate an error in design rather than a runtime error.
The NSError** idiom is all you need for things such as failed URL connections, data conversions, etc, where an error condition exists but a program really shouldn't be killed outright.
Start reading: Error Handling Programming Guide

Garbage value undetected in debug mode

I've recently discovered the following in my code:
for (NSInteger i; i<x; i++){
...
}
Now, clearly, i should have been initialised. What I find strange is that while in "debug" profile (XCode), this error goes undetected and the for loop executes without issue. When the application is released using the "release" profile, a crash occurs.
What flags are responsible for letting this kind of mistake execute in "debug" profile?
Thanks in advance.
This could be considered a Heisenbug. A declaration without an initialization will typically allocate some space in the stack frame for the variable and if you read the variable you will get whatever happened to be at that location in memory. When compiled for the debug profile the storage for variables can shift around compared to release. It just happens that whatever is in that location in memory for debug mode does not cause a crash (probably a positive number) but when in release mode it is some value that causes a crash (probably a negative number).
The clang static analyser should detect this. I have the analyse when building option switched on always.
In the C language, using an initialized variable isn't an error but an Undefined Behavior.
Undefined behavior exists because C is designed to be a very efficient low-level language. Using an initialized variable is undefined behavior because it allows the compiler to optimize the variable allocation, as no default value is required.
But the compiler is licensed to do whatever he wants when an undefined behavior occurs. The C Standard FAQ says:
Anything at all can happen; the Standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
So any implementation of an undefined behavior is valid (even if it produces code that formats your hard drive).
Xcode uses different optizations for Debug and Release configurations. Debug configuration has no optimization (-O0 flag) so the compiled executable must stays close to your code, allowing you to debug it more easily. On the other hand, Release configuration produces strongly optimized executables (-Os flag) because you want your application to run fast.
Due to that difference, undefined behaviours may (or may not) produce different results in Release and Debug configurations.
Though the LLVM compiler is quite verbose, it does not emit warnings by default for undefined behaviors. You may however run the static analyzer, which can detect that kind of issues.
More information about undefined behaviors and how they are handled by compilers in What Every Programmer Should Know About Undefined Behavior.
I doubt it is so much flags as the compiler is optimizing out the "unused" variable i. Release mode includes far more optimizations then debug mode.
Different compiler optimizations may or may not use a different memory location or register for you uninitialized variable. Different garbage (perhaps from previously used variables, computations or addresses used by your app) will be left in these different locations before you start using the variable.
The "responsibility" goes to not initializing the variable, as what garbage is left in what locations may not be visible to the compiler, especially in debug mode with most optimatizations off (e.g. you got "lucky" with the debug build).
i has not been initialized . You are just declaring the i variable not initializing the variable.
Writing just NSInteger i; just declares a variable not initializes it.
You can initialize the variable by below mentioned code.
for (NSInteger i=1; i<x; i++){
...
}

Objective-C: Assertion vs. Exception vs. Error

In Cocoa, when should I use NSAssert, NSException, NSError?
Here's what I've been thinking:
NSAssert - When creating any client program used for the programmers own benefit to double check rules, conventions, assumptions, or pre-conditions and post-conditions?
NSException - When creating a third-party library for the benefit of other programmers that use the library, so that they immediately know when an input is invalid?
NSError - When interfacing with an external system to get data like a file, database, or web service that isn't guaranteed to give me a result?
An NSAssert will throw an exception when it fails. So NSAssert is there to be short and easy way to write and to check any assumptions you have made in your code. It is not (in my opinion) an alternative to exceptions, just a shortcut. If an assertion fails then something has gone terribly wrong in your code and the program should not continue.
One thing to note is that NSAssert will not be compiled into your code in a release build, so this is typically used for sanity checking during development. I actually tend to use a custom assert macro that is always active.
The times you would #throw your own NSException are when you definitely want it in a release build, and in things like public libraries/interface when some arguments are invalid or you have been called incorrectly. Note that it isn't really standard practice to #catch an exception and continue running your application. If you try this with some of Apple's standard libraries (for example Core Data) bad things can happen. Similar to an assert, if an exception is thrown the app should generally terminate fairly quickly because it means there is a programming error somewhere.
NSErrors should be used in your libraries/interfaces for errors that are not programming errors, and that can be recovered from. You can provide information/error codes to the caller and they can handle the error cleanly, alert the user if appropriate, and continue execution. This would typically be for things like a File-not-found error or some other non-fatal error.
The convention in Cocoa is that an exception indicates a programmer error. A lot of code, including framework code, is not designed to work properly after an exception is thrown.
Any sort of error that should be recoverable is represented by an NSError. There’s also a system for presenting NSErrors to the user. As you say, this is mostly useful for fallible external resources.
Conceptually, an assertion is a statement that a given predicate always evaluates to true; if it doesn’t, the program is broken. While its behaviour can be modified, the NSAssert family is by default a convenient way of throwing NSInternalInconsistencyExceptions (with the option of turning them off in release builds).
Edit:
In Xcode 4.2, assertions are turned off by default for release builds,
Now NSAssert will not be compiled into your code in a release build, but you can change it in build settings
#Mike Weller, There are one wrong in your answer.
One thing to note is that NSAssert will not be compiled into your code in a release build, so this is typically used for sanity checking during development.
Actually, NSAssert will be compiled into your code if you don't add NS_BLOCK_ASSERTIONS in your precompiled prefix files.
In Technical Note TN2190 we can find:
Macros like NDEBUG to turn off C assert or NS_BLOCK_ASSERTIONS to turn off Foundation's NSAssert are important to specify for your precompiled prefix files
Or you can read this one:How to know if NSAssert is disabled in release builds?
In general, exceptions are used to signal programmer errors — they're things that shouldn't happen. Errors are used to signal error conditions that might come up in the normal operation of the program — user errors, basically, or external conditions that need to be true but might not be. So trying to delete some locked element in a document might be an error, and trying to download a file without an Internet connection would be an error, but trying to access an invalid element in a collection would be an exception.
Assertions are typically used in testing, and AFAIK are not used as a general error-handling mechanism like the others.

What’s the rationale behind the Cocoa exception policy - or why use exceptions only for programmer errors?

What’s the rationale behind the Cocoa exception policy - or why use exceptions only for programmer errors?
I understand that exception used to be rather expensive so one would not want to overuse them. But that changed with the modern runtime and it’s zero-cost exceptions. I also understand that the use of exceptions to do general control flow is not a good idea because it could lead to code that is rather hard to understand.
But why should one use exceptions to signal programmer errors? For that case logging a message followed by abort() should be enough. Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake? I’ve been thinking about this a lot and I haven’t found any reasonable use of an exception for a programmer error.
(As a side note/question: I’ve written a recursive descent parser, and I’m planning on using exceptions in there for handling errors. Seems to be much more reasonable to me than adding an out parameter to every single function in there and manually check for an error everywhere. Of course I’ll catch any exceptions I throw in the top level methods that get called from the outside. Anyone think that’s a bad use for exceptions?)
Update: The real question
Thanks for all the answers so far. They all are true, but they don’t actually answer my question. So I guess I wasn’t really clear about it, sorry for that. So here’s the real question:
Why does Cocoa throw exceptions for programmer errors (or assertions) at all? One isn’t supposed to catch them, and actually writing code that handles a programmer error somewhere down the call stack is not a good idea anyways. Seems to me that exceptions there are a wasted effort. Simply logging the error and calling abort() (which exits the program) should be enough. So what’s the advantage there of actually having an exception thrown?
I understand why exceptions are not generally used and discouraged - most parts of Cocoa are just not exception safe. And that’s not the question here. I hope I made this clear now.
Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake?
In most cases, you wouldn't. In Objective-C, you generally don't handle exceptions. If an exception occurs, it causes a crash, and then you fix the bug -- hopefully you catch this during testing.
Of course, in some cases this doesn't work out. Maybe you do except an exception and you can workaround it, so you catch it. Or there's there rare API that'll throw exceptions instead of using error objects.
To be honest, I very, very rarely use try/catch in my Objective-C code.
As for the rationale, I think it's largely due to Objective-C's C heritage. Back in the early 80s when Objective-C was developed, exceptions were kind of "new" (i.e., not in many mainstream languages yet), and Objective-C catered more to the C tradition of using NULL or an out parameter to signal errors.
Your question explicitly assumes that "one isn’t supposed to catch them." This is incorrect. The programmer isn't expected to catch them under normal circumstances, but that isn't to say that they must never be caught for any purpose.
Example: I'm not sure if it does anymore since it's much less buggy these days, but I know it at least used to be the case that Xcode would catch exceptions and put up a dialog saying, "Such-and-such happened. It doesn't appear to be a critical problem, but you should probably save and restart the program to avoid any trouble in the future."
Why does Cocoa throw exceptions for
programmer errors (or assertions) at
all? One isn’t supposed to catch them,
and actually writing code that handles
a programmer error somewhere down the
call stack is not a good idea anyways
Ah!
Three reasons leap to mind.
One, if you catch an exception more or less at your main run loop you could autosave state to a temporary location, crash, and on restart have a "try to restore from just before the crash, warning: may cause another crash and you should check your data very carefully" dialog/sheet/thingie. Or even just catch the exception and tell the user to do a "Save As", quit and restart.
Two, things like the unit test framework make good use of exceptions to abort the current test (logging a failure), and continuing with the rest of the tests. This lets you see if a change you made has one regression (that happens to index a NSArray out of bounds), or if you have six regressions (one or more of which throw an exception).
Three, maybe when added to ObjC it was intended to handle many kinds of errors with exceptions, and after real world experience the useful scope was determined to be "nearly fatal errors only".
The main reason for avoiding throwing exceptions is that you may accidentally throw them through stack frames that are not exception aware. For instance, if a data source for a table view throws an exception, that is not caught and handled before the delegate method returns control to the table view, it might cause all sorts of trouble as it unwinds the table view's stack frames, side stepping various releases of temporary objects and other resources.
Having said that, I personally like exceptions and use them wherever I think they are the natural thing to do, but with the caveat of never allowing them to propagate to code that is not documented as exception aware.
There are likely a lot of reasons. The "historical reasons" others have covered is sufficient to explain the current state of affairs, but there are other possibilities.
Another possibility is Objective C is not typically a "Resource Acquisition Is Initialization" kind of language (yes this is more a library issue then a language issue, but it is real). So most Objective C code that has an error thrown through it will leave invalid program state (things still locked, over retained objects). All things you could deal with if you were thinking about it, and not all things RAII would magically fix (there is a lot of exception unsafe C++ code out there, and C++ is largely RAII).
As noted above stating that you do handle an exception is free(ish), but actually having one thrown is costly (maybe an order of magnitude or two more costly then an extra parameter and a conditional check). So if your parser (for example) uses them to signal errors in parsing, being given a document with a lot of errors can take a LOT longer to parse then if you had explicit checks for an error parameter.
Personally I like exceptions, and would prefer to throw exceptions from my libraries when things "go wrong", but that isn't the Cocoa way, so I use exceptions to handle programmer errors and an error indication and NSError** for other things. It isn't great, but it makes it so other people can use my libraries without having to learn a new way to write Objective C code.
The modern runtime does not give you zero-cost exceptions, it gives you exceptions that only incur their cost if an exception is thrown.