| |
 | Posted by Jonathan M Davis in reply to Dave P. | Permalink Reply |
|
Jonathan M Davis 
Posted in reply to Dave P.
| On Thursday, April 17, 2025 11:36:49 AM MDT Dave P. via Digitalmars-d wrote:
> On Thursday, 17 April 2025 at 16:39:28 UTC, Walter Bright wrote:
> First to support classes, you’d have to make a slight change
> ```d
> struct NonNull(T)
> {
> T p;
> T ptr() { return p; }
> alias this = ptr;
> }
> ```
>
> It works, but the syntax/defaults is backwards. Why does the unusual case of a nullable pointer get the nice syntax while the common case gets the `NonNull!(int*)` syntax? Who is going to write that all over their code?
I am in favor of making changes along the lines that Rikki is proposing so that we can better handle failure in multi-threaded environments without having to kill the entire program (and in addition, there are cases where dereferencing null pointers is not actually memory-safe, because either that platform doesn't protect it or a compiler like ldc or gdc will optimize the code based on the fact that it treats null pointer dereferencing as undefined behavior).
That being said, I honestly think that the concern over null pointers is completely overblown. I can't even remember the last time that I encountered one being dereferenced. And when I have, it's usually because I used a class and forgot to initialize it, which blows up very quickly in testing rather than it being a random bug that occurs during execution. So, if someone feels the need to use non-null pointers of some kind all over the place, I'd be concerned about how they're writing their code such that it's even a problem - though it could easily be the case that they're just paranoid about it, which happens with sometimes with a variety of issues and people. And as such, I really don't think that it's all that big a deal if a wrapper type is required to guarantee that a pointer isn't null. Most code shouldn't need anything of the sort.
However, as I understand it, there _are_ memory-safety issues with null pointers with ldc (and probably gdc as well) due to how they optimize. IIRC, the core problem is that they treat dereferencing a null pointer as undefined behavior, and that can have serious consequences with regards to what the code does when there actually is a null pointer. dmd doesn't have the same problem from what I understand simply because it's not as aggressive with its optimizations. So, Walter's stance makes sense based on what dmd is doing, but it doesn't necessarily make sense with D compilers in general.
So, between that and the issues with platforms such as webasm, I am inclined to think that we should treat dereferencing pointers like we treat accessing elements of arrays and insert checks that the compiler can then optimize out. And we can provide flags to change that behavior just like we do with array bounds checking. But if we cannot guarantee that attempting to dereference a null pointer is always @safe (and as I understand it, outside of using dmd, we can't), then that's a hole in @safe. And no matter how rare dereferencing null is or isn't in practice, we can't have holes in @safe and have it actually give guarantees about memory safety.
- Jonathan M Davis
|