I’m with you that it’d be nice to not need any type of GC background process, but aside from Rust’s model I just can’t think of a way to do that. This was the best I could do at minimizing it, and working with Unity where you have to actively avoid the GC, at least this way it doesn’t get in the way of doing real-time work. To actually get away from it, you’d need to either do some self-management of pools or not allow tasks to create new ones, and then you have to be really careful to not run out of memory.
As far as your concern about leaking being bad, I agree that it’d probably put some people off, although I don’t think that’s necessarily rational - real GC languages do that too, it’s just you have more of a guarantee that memory will be available when you need it. I think the biggest issue here is you’d have to be really aware of how much memory you’re going to need for each task, otherwise you could easily run out if you have a few concurrent tasks that take more than you expected. You’d have to make sure that if your usage was unbounded you use a real allocator and RAII. It also would make allocation really tedious, because you have to either handle the error case everywhere (imagine if Box::new returned an Option in Rust) or accept that tasks crash like Erlang, which needs a runtime. I don’t really like either of those.
I’m thinking though, it might work to not encourage leaking but just say don’t worry about it too much? So you’d use RAII objects, but in the case where you have cycles or shared references, you just forget about it and they’ll be reclaimed when the task finishes. I think you could even get by without a runtime if you have language support for tasks as regions and don’t build in green threads like Go. The pool manager would post notifications about memory usage to a user defined callback, which you could either handle yourself or use the default background thread handler.
Not sure how threading would work yet, since that would not be a subset of the parent task unless you had something like rayon::Scope. I guess you’d need some type of move/copy semantics between regions, and probably refcounted pointers.
Hmm, FFI is gonna be tricky. I guess you’re kind of on your own there. I think maybe to make it safer you’d restrict it to memory that’s not part of an auto-freed pool, although I think it should be up to the user to decide whether that particular call holds on to the memory or not.
I think if I go too much further I’m just going to end up confusing myself, but go ahead and nitpick, I need it if I’m gonna have any chance of making this work.