← Back to context

Comment by stymaar

14 hours ago

> mem::forget isn’t the only way you can safely leak a value, you can do it with reference cycles too, right? And there is no way for the compiler to detect that?

But there's an easy solution for that: you make the reference-counted smart pointers require their pointee type to be Forget. It will be like how Arc<T> doesn't implement Send unless <T: Sync>.

An alternative way to "forget" a value is to hand it off to another thread that then loops infinitely.

Could of course be plugged by saying `!Forget : !Send`, but wouldn't that preclude legitimate useful scenarios for `!Forget`?

  • The more accurate definition of `!Forget`, similar to `Pin<&mut !Unpin>`, is not "can be leaked" but "if the underlying storage is reused, the destructor is guaranteed to run". This enables all important (decidable - preventing leaking is undecidable, even in GC languages) use-cases, and sending the value to a thread does not break this contract.

  • Passing ownership to another thread is not the same as forgetting/leaking.

    The point of !Forget is ensuring that once the owner goes out of scope the destructor must be guaranteed to run. An infinite loop is not a problem, cause the new thread will never leave its scope. Ref-cycles are a problem, cause you can create a ref-cycle. Then the program flow leaves the scope which will run the drop on all RC's but not the drop on the inner type.

  • > An alternative way to "forget" a value is to hand it off to another thread that then loops infinitely.

    Might be able to address that by only allowing such a handoff to a thread spawned via some scoped abstraction to ensure that progress can only be made if/when the spawned thread terminates?