I'm normally in the `It's shit, end of discussion' camp, but recently I've been thinking that this is really caused by attempting to bolt it onto C-like languages. The problem is that GC has to, one way or another, at some point know exactly whether an allocated object is reachable from current context. What makes this hard is that you can take arbitrary references to an object in C/Java/Sepples/etc. If the following code were illegal:
o = create_some_big_object(); a = o; do_something_with_object(o); do_something_else_with_object(a);
Because a and o were both references to the same memory, GC would be a lot better. So if you had a language that operated kind of like this:
object *o, a, b; // All implicitly (or explicitly) NULL create_some_big_object(&o); // The memory is created with exactly one reference transfer_reference(&o, &a); // The memory still has exactly one reference - o is NULL'd // do_something_with_object(o); // This would be illegal, o is NULL do_something_with_object(a); // This is fine copy_reference(&a, &o); // Now the memory has exactly two references do_something_with_object(o); // This is now fine transfer_reference(&b, &o); // Still two references close_reference(&b); // Now one reference - a transfer_reference(&b, &a); // Now one reference - b close_reference(&b); // Now zero references, memory is reclaimed at exactly this point.
I think Rust is doing something along this path, with owned references and transferring references, but I haven't had time to look into Rust (partially because every time I look at it they've made major structural changes to the language, and I want to wait for it to settle down), and I'm sure there have been languages in the past that did this, but I haven't seen any. Obviously, the syntax is shit in my example, but I think the basic point: that you have to explicitly duplicate references, could make it work.
The bit where this would really work is in the case where you transfer a reference into a field of a structure, because close_reference could do a walk and sanely close out child references as well, and transfer_reference can sanely close references to its clobbered arg.
But obviously, this doesn't work too well when you have a language that allows programmers to skip close_reference, or to take pointers in any other method than from creation or copy_reference, etc. Sepples tried something like this with RAII, but I wouldn't exactly call Sepples a model of perfection for that. So in order to create this model as a usable language, I think C-ish syntax would have to be thrown away.