Avoid a Void: eradicating null-pointer dereferencing
lambda-the-ultimate.org
lambda-the-ultimate.org
if ([[obj delegate] shouldThisDoSomething]) { ... stuff ... }
When calling "delegate" on obj, it might return nil if there isn't one set (or if obj itself is nil). If it does return nil, sending "shouldThisDoSomething" results in 0 (aka nil). nil == false, So "stuff" will never happen - which is pretty much as expected in 99%* of cases. (* made up statistic)This behavior, combined with a few rules like naming certain methods in a way that asks permission rather than forbids an action, gets you an entire system where you can almost completely forget about the issue while retaining programmer control for the few special cases where it might matter and you can test for it.
(Nil also sticks out like a sore thumb in the debugger if you're stepping through and trying to figure out why something didn't work like you thought it should.)
Aside: Nothing fails silently unless you never test it. It's just a matter of how you're exposed to the failure. IMO, sending to nil resulting in 0/nil is very good at eliminating a lot of if/else boilerplate for certain situations which means less code cluttering my screen.
>
> x.f (args)
>
> x, a reference, should normally denote an object but can
> be void, in which case the call will fail and produce an
> exception, often leading to a crash. *This is one of the
> main sources of instability in today's software.*
Says who ?I have been routinely programming in C++ for the last 10 years and not only I have not ran into this sort of bug in my own code, I have never seen it encountered by anyone else in my vicinity. I understand they wanted to create a dramatic backdrop for some cool new feature they are really proud of, but conjuring facts out of thin air is not a way to do it.
Bla x = someFunctionThatMightReturnNull();
if(x.foo()) ...
Sure, people should check the return value, but that check is often forgotten, especially if x.foo() is some sort of validity or integrity checking. It's an edge case.And really, a proof by "I've-never-seen-it" seems like a weak justification for accusing researchers of "conjuring facts out of thin air". If you're actually interested, the article by Tony Hoare (which was also posted on LTU) provides provides more concrete figures, if I recall. I think it's pretty well understood as a very common error.
I'd be interested to know what you think common sources of instability are in your experience?
If you have a link for the Tony Hoare article, it'd be interesting to see what its sampling base was.
You didn't answer my question, either. What do you think are the most common sources of instability?
Not once we had a recorded bug caused by calling a class method on a null pointer. If the code is operating with references, it requires some ingenuity to return a null reference from a function. And if the code operates with pointers, the null checks are typically there. So, yeah, the p->foo() with p being null is a very uncommon issue.
With regards to what are the common sources of instability are - based strictly on my experience, the "instability" in C++ context typically comes from not enforcing class invariants, or not adhering to the declared class semantics. This clearly can come in a variety of forms and shapes, and it is hardly possible to pinpoint specific language construct as a single most common root of these problems. Also, I frankly do not remember when was the last time we had an actual crash in our production code. In C context the sources of crashes vary, but more often than not they are caused by the side effects of the functions, i.e. you have a data structure (pointed at or allocated in some other fashion), you feed it to the function and this call invalidates it, but you assume it does not. This sort of thing. Again, if there are pointers, then any C programmer worth his salt will have either an assert or a conditional right after where this pointer is initialized or changed. I have never seen a bug caused by calling a null function pointer, and there is some code that makes a very extensive use of them.
Hopefully this answers your question.
Now, how about the link to that article ?
http://lambda-the-ultimate.org/node/3186
From what you've said, it sounds like your code (and perhaps team?) are better than average. You say yourself, you haven't had an actual crash since you can remember. If you were having crashes, then my money would be on them being caused by one of: null references (which generally just falls into the category of "not checking return values") and not accounting for edge cases. But you don't have crashes, so all of this is a little bit speculative, isn't it?