Pointers are memory safe as long as Unchecked_Deallocation/Unchecked_Access are never used thanks to how pointers have scopes, even though pointers can be pointing to variables on the stack.
You can go a very long way without ever touching Unchecked_Deallocation compared to C or Rust, even without allowing for use of the standard library where deallocation is done under the hood. I use it rarely enough that I have to go check the package specification every time I need it.
You also have relatively safe deallocation when you wrap your allocation in a storage pool and let RAII deal with it as the pointer system keeps you safe from a dangling reference if your container type only frees memory within the Finalize procedure.
You don't have the complete memory safety of a GC or Rust's borrow checker without SPARK, but you can completely avoid the unsafe parts or use well tested containers as opposed to C and other similar language where you need unsafe pointers to do anything non-trivial.
You can go a very long way without ever touching Unchecked_Deallocation compared to C or Rust, even without allowing for use of the standard library where deallocation is done under the hood. I use it rarely enough that I have to go check the package specification every time I need it.
You also have relatively safe deallocation when you wrap your allocation in a storage pool and let RAII deal with it as the pointer system keeps you safe from a dangling reference if your container type only frees memory within the Finalize procedure.
You don't have the complete memory safety of a GC or Rust's borrow checker without SPARK, but you can completely avoid the unsafe parts or use well tested containers as opposed to C and other similar language where you need unsafe pointers to do anything non-trivial.