"Premature optimization.... " you get the drift.
IMO, even though this is C, the Zen of Python still applies, which states:
> Errors should never pass silently unless explicitly silenced.
Its the caller with the bug, not the library code.
Then the type of the function would just declare a that the pointer can't be null, and code which sends a nullable pointer would refuse to compile.
Make it right
Make it fast
This is an ordered list, and the people who forget that make a lot of work for the people who don’t
It's definitely not right, while probably not really working either. The immaterial performance gain from removing the null check is completely irrelevant.
It's a foot-gun for sure, but it's up to you to not pull the trigger.
There are several comments indicating the performance cost of a NULL check. Go and look at the disassembler and see the code. You should find that it equates to JZ, which at worst case costs 1 clock cycle. Am I incorrect?
So, another comment below mentioned 10 million deletions per second. Ignoring the fact that you should be using a double linked list at that point (like the kernel does), in a single threaded 2.4GHz CPU a 1 step opcode (JZ) equates to a bit over 4ms/sec. With branch prediction, I expect to be far less.
So, the NULL check is almost free. Even on embedded systems, it'd still be a good idea to keep it in, to insulate yourself from flipped bits (eg, solar flares, or degrading memory) and coding mistakes elsewhere.
In these days of security research, I strongly advise for defensive code: it means that each function has had it's edge cases thought about, which means the developer has spent time thinking about the stability of their program, which cannot be a bad thing. Don't make your code a deliberate point of exploitation.
I guess my question is, what's wrong with crashing, in the case of a real screwup, where something has gone horrible wrong, assuming you have a proper crash handler?
I can fail so you can catch it, or if you don’t catch it, you’ll at least see exactly what went wrong. You expected the item to be in the list and it wasn’t. Your preconditions were wrong from the beginning and you have an (unknown) bug in the code.
The alternative is that I can’t find the item and I silently suck it up and don’t notify you. If that’s the api we’ve all agreed on, that’s fine. It was on you to check for the thing in the list first and then remove it. But it’s a bit weird if you think about it - now you need to traverse the list twice. Once to check for the existence (and fail out yourself) and once to remove.
next?.doThing()
Where doThing is never called if next is null.Languages that do this use "scary" operators to crash on null:
next!!.doThing()
And it's drilled into people's heads the latter is a Bad Thing (tm)-
You really need to consider context in null handling.
Imagine an app that alerts a nurse when the patients heartbeat is out of range.
In an application where the UI context might have been closed out, it's common to see
someUiContext?.showAlert()
But what actually happens if the context is gone?It's better to crash and have part of your startup procedure be communicating that a crash occurred, and the doctor should check that something went wrong, than silently continuing.
-
The problem is when you tell people this, the kneejerk reaction is always "are you saying we intentionally add crashes"!
Because safe null handling was specifically added to avoid the situation where that crashes...
(For example, if the app was a news reader and the alert was "Article failed to load", you wouldn't want the app to crash just because the user left a certain page before the alert was shown)
But I think the pendulum has swung too far at this point, people are so used to just sweeping nulls under the rug, and it's not great for finding issues
Sure you could make the argument that we don't _know_ they are being checked, but it's a pointless discussion. Who cares? _If_ preconditions are met, this code is safe, if they aren't, it's not safe. Since we don't know one way or the other, there's no point in discussing further. The kernel developers know their stuff...
From a black box, zero-knowledge, perspective it’s maybe worth remembering that code built this way successfully runs mission critical systems all over the world every day. Thoughtful people would have switched to other (slower, more pedantic) systems if doing things differently was a real overall life improvement. People have had the choice, there are plenty of OS’s out there... some far more formal/pedantic. Linux wasn’t the safe choice back in the day, it was just better by several important metrics consistently over time.
Perhaps these insanely experienced kernel devs know what they are doing.
Imagine if at every function down a complex stack you go with:
if (!ptr1 || !*ptr1 || *ptr1 > 5 || param1 < 0 || param2)
/* etc.... */
{
return NULL;
}
(used arbitrary names and values).I'm sorry if this might be common knowledge, but I've honestly never heard this and can't understand it.
Is it saying that it's better to do something than to (formally) prove it, like the opposite of (I think) Knuth's famous quote?