No... And yes.
No: Because throwing and catching the null pointer exception is hideously slow compared to doing a null check. In Java / C#, the exception is an allocated object, and the stack is walked to generate a stack trace. This is in addition to any additional lower-level overhead (panic) that I don't understand the details well enough to explain.
Yes: If, in practice, the pointer is never null, (and thus a null pointer is truly an exceptional situation,) carefully-placed exception handlers are an optimization. Although, yes, the code will technically be faster because it's not doing null checks, the most important optimization is developer time and code cleanliness. The developer doesn't waste time adding redundant null checks, and the next developer finds code that is easier to read because it isn't littered with redundant null checks.
True for 99% of programming jobs, but if you are worried about the speed of null checks, you are in that 1%.
In high frequency trading, if you aren’t first your last and this is the exact type of code optimizations you need for the “happy path”
That's also rather... Redundant in modern null-safe (or similar) languages.
IE, Swift and C# have compiler null checking where the method can indicate if an argument accepts null. There's no point in assertions; thus the null reference exceptions do their job well here.
Rust's option type (which does almost the same thing but trolls love to argue semantics) also is a situation where the compiler makes it hard to pass the "null equivalent." (I'm not sure if a creative programmer can trick the runtime into passing a null pointer where it's unexpected, but I don't understand unsafe Rust well enough to judge that.) But if you need to defend against that, I think Panics can do it.
Thus, in the real world null can never occur--but there are a gazillion places where it would have to test for a null that should never happen. Or simply Assert in the routine itself.
I'm not. It's pretty clear that you don't know how null safe Swift, C#, and Rust work.
IE: Rust has the option type for when a value can be null, and the compiler forces you to do an "empty" check. Otherwise, null, does not exist in the language.
Swift and C# are more metadata based. You indicate if a value supports null or not. The compiler will give you a warning, or error depending on configuration, if you try to assign null to a value that does not expect it.
All three languages have a concept of values that can be null, (or empty in Rust if you want to argue semantics,) so your type system tells you when a value can be null, or when it is expected to not be null. In all three languages, the compiler can force you to make assignments before you use an object.
C# has https://learn.microsoft.com/en-us/dotnet/csharp/nullable-ref...
Of course, there's a big difference between doing it in a VM and doing it in a random piece of software.
On every pointer deref in your entire program. Not for release mode.
But you're saving probably two bytes in the instruction stream for the test and conditional jump (more if you don't have variable length instructions), and maybe that adds up over your whole program so you can keep meaningfully more code in cache.
It's UB so you are forever gonna be worrying about what weird behaviour the compiler might create. Classic example: compiler infers some case where the pointer is always NULL and then just deletes all the code that would run in that case.
Plus, now you have to do extremely sketchy signal handling.
Unlike crummy barely more than a macro assembler compilers of yore. A modern compiler will optimize away a lot of null pointer checks.
Superscalar processors can chew gum and walk at the same time while juggling and hula hooping. That is if they also don't decide the null check isn't meaningful and toss it away. And yeah checking for null is a trivial operation they'll do while busy with other things.
And the performance of random glue code running on a single core isn't where any of the wins are when it comes to speed and hasn't been for 15 years.
Also, so long as the hardware ensures that you don't get away with using the null I would think that not doing the test is the proper approach. Hitting a null is a bug, period (although it could be a third party at fault.) And I would say that adding a millisecond to the bugged path (but, library makers, please always make safe routines available! More than once I've seen stuff that provides no test for whether something exists. I really didn't like it the day I found the routine that returned the index of the supplied value or -1 if it didn't exist--but it wasn't exposed, only the return the index or throw if it didn't exist was accessible.) vs saving a nanosecond on the correct path is the right decision.
Is this actually a real optimization? I understand the principal, that you can bypass explicit checks by using exception handlers and then massage the stack/registers back to a running state, but does this actually optimize speed? A null pointer check is literally a single TEST on a register, followed by a conditional jump the branch predictor is 99.9% of the time going to know what to do with. How much processing time is using an exception actually going to save? Or is there a better example?