On 03/07/2012 11:17 PM, Jonathan M Davis wrote:
On Wednesday, March 07, 2012 22:58:44 Chad J wrote:
On 03/07/2012 10:40 PM, Jonathan M Davis wrote:
On Wednesday, March 07, 2012 22:36:50 Chad J wrote:
On 03/07/2012 10:08 PM, Jonathan M Davis wrote:
On Wednesday, March 07, 2012 20:44:59 Chad J wrote:
On 03/07/2012 10:21 AM, Steven Schveighoffer wrote:
You can use sentinels other than null.
-Steve
Example?
Create an instance of the class which is immutable and represents an
invalid value. You could check whether something is that value with the
is operator, since there's only one of it. You could even make it a
derived class and have all of its functions throw a particular exception
if someone tries to call them.
- Jonathan M Davis
Makes sense. Awfully labor-intensive though. Doesn't work well on
classes that can't be easily altered. That is, it violates this:
- Do not modify the implementation of UnreliableResource. It's not
always
possible.
But, maybe it can be turned it into a template and made to work for
arrays too...
Personally, I'd probably just use null. But if you want a sentinel other
than null, it's quite feasible.
- Jonathan M Davis
Wait, so you'd use null and then have the program unconditionally crash
whenever you (inevitably) mess up sentinel logic?
Yes. Proper testing will find most such problems. And it's not like having a
non-null sentinel is going to prevent you from having problems. It just means
that you're not distinguishing between a variable that you forgot to
initialize and one which you set to the sentinel value. Your program can die
from a variable being null in either case. And in _both_ cases, it's generally
unsafe to continue executing your program anyway.
The important difference in using explicit sentinel values here is that
they are not null, and thus very unlikely to have been caused by memory
corruption. It allows us to distinguish between the two sources of
empty variables.
With a better way to do sentinel values, I can isolate my cleaner
looking code from the scarier looking code that comes from any number of
places.
I also am not too worried about null values that come from stuff that
was simply forgotten, instead of intentionally nulled. I DO tend to
catch those really early in testing, and they are unlikely to happen to
begin with due to the close association between declaration and
initialization.
And honestly, in my experience, null pointers are a very rare thing. You catch
them through solid testing.
- Jonathan M Davis
Sorry, your testing doesn't help me as well as you probably wish it
does. Our experiences must be very different. I run into a lot of
cases where things can't be tested automatically, or at least not
easily. Think along the lines of graphics operations, interactively
driven code (ex: event lifetimes), network code, etc. Testing can help
things between endpoints, but it doesn't help much where the rubber
meets the road.
And that's just game dev. Then I go to work at my job, the one that
makes money, and experience code from the 80s. Rewriting it is
completely impractical for near-term projects (though a complete
phase-out of crufty old crap is on the horizon one way or another!).
Yes it has bugs. If I had an attitude of "crash on every little nit"
then these things wouldn't last a few seconds (OK, exaggeration). So I
recover as well as possible, and occasionally rewrite strategically
important pieces. But the world is NOT perfect, so relying on it being
perfect is %100 unhelpful to me. Also, "quit your job" is not an
acceptable solution. ;) Now, in principle, we will never have to deal
with D code like that. Nonetheless, these experiences do make me
severely afraid of lacking the tools that keep me safe.
And then there are still those occasional weird problems where sentinel
values are needed, and its so stateful that there's a vanishingly
close-to-zero chance that testing will catch the stuff that it needs to.
So I test it as well as I can and leave a "if all else fails, DO THIS"
next to the dubious code. Indiscriminate segfaulting deprives me of
this last-ditch option. There is no longer even a way to crash
elegantly. It all just goes to hell.
Long story short: in practice, I find that recovering from sentinel
dereference is not only VERY safe, but also orders of magnitude less
frustrating for both my users and me.
(Memory corruption, on the other hand, is something I am very unfamiliar
with, and sort of afraid of. So I'm willing to ditch nulls.)