Seamless interop with C, even when cross compiling which Zig handles natively: the standard install of Zig comes with a "zig cc" wrapper around clang that allows you to cross compile[2][3] C and zig code for any number of target architectures (it includes C standard library headers and code for them).
Zig is the only language I've come across which functions perfectly as a better C.
[1]: https://ziglang.org
[2]: https://actually.fyi/posts/zig-makes-rust-cross-compilation-...
[3]: https://andrewkelley.me/post/zig-cc-powerful-drop-in-replace...
Most of the time (in my practice, like 99% of the time) you don't have to care about nulling references. The objects that need collection are created in local scopes of functions, and get detached and ready for GC right when the function returns. When you have many small functions, this happens often, so unused objects don't spend much time being referenced and ineligible for GC.
The problematic part is long-living mutable structures, which you hopefully have few, and know well where they are in your code.
Also, as an exercise, I suggest that you try to imagine a Lisp with explicit memory management.
Remembering to null references is not much easier than remembering to delete things. It's trading one issue for another.
And now there's two ways to remember to manage memory.
There are exceptions to that, like queues and caches, but they are few and should be closely watched.
I already write web services in Rust. It's no more difficult than Java or Python.
I can't wait for the ecosystem to heat up more, because it'll make it compelling to switch to Rust at work.
But if you care enough to be writing tests or put lots of thought into API and schema, then maybe you're in the disciplined camp that would get a ton of benefit from switching.
If you're using C++, you should switch for any greenfield project that doesn't need to use legacy libraries. (Writing wrappers for C libraries isn't hard at all.)
Typically I just use weak references or weak reference sets/dicts/whatever. That's python for you though.
I presume you mean it's just as hard in some specific language, not just as hard in general.
Its as much work to use a garbage collector efficiently as it is to allocate and delete your own memory. And with about the same bugs. It's been problematic from the start.
Not a fan of automatic systems to 'manage' memory. Overhead for automatic systems create lag, latency and bloat. I'm old-fashioned, and create code that has strict ownership of allocated memory by subsystem. If a module that allocates also frees, leaks become negligible. If references are not shared but accessed formally, nulls become returned errors etc.
Discipline is hard, but leaky buggy garbage-collecting behemoths are hard to live with too.