The rant about OOP and responsibilities is completely way off mark.
It is not a firm rule of OOP that a module has to clean up all the resources it allocates and never pass any of them off to be cleaned up elsewhere.
This is violated all over the place with layering. For instance, instead of allocating a buffer here and then having someone free it, we can create a Message class which has a buffer. We now send a Message from one module to another. Oh, the buffer is now a single responsibility: it is allocated by the Message module and freed by the Message module. But all we have done is wrap the resource in a trivial class; the design hasn't really changed. We can have a semantic leak if we start creating Messages and stuffing them into some queue which nobody dequeues, just like with the original buffers.
Layering of ownership creates the appearance that one module is managing a resource. That module's instances, though, can be created by one higher layer module and released by another.
I'd point out that afaik rustc never got a proper good GC implementation (which probably weighted heavily in the decision to remove it before 1.0), so @T/Gc<T> were mostly plain old refcounted pointers with some smoke and mirrors.
See http://words.steveklabnik.com/pointers-in-rust-a-guide for example (section "Managed pointers")
This is the TXR Lisp interactive listener of TXR 181.
Quit with :quit or Ctrl-D on empty line. Ctrl-X ? for cheatsheet.
1> (defstruct raii-class nil
(:init (me) (put-line "raii-class hello"))
(:fini (me) (put-line "raii-class goodbye")))
#<struct-type raii-class>
2> (with-objects ((o (new raii-class)))
(put-line "inside block"))
raii-class hello
inside block
raii-class goodbye
t
Constructor abort via non-local transfer: 3> (defstruct ctor-throws nil
(:init (me) (error "refuse to init"))
(:fini (me) (put-line "ctor-throws goodbye")))
#<struct-type ctor-throws>
4> (new ctor-throws)
ctor-throws goodbye
** refuse to init
** during evaluation at expr-3:2 of form (error "refuse to init")
:fini called by GC: 5> (progn (new raii-class) nil)
raii-class hello
nil
6> (sys:gc)
raii-class goodbye
t
with-objects is not just with structs but for anything with a GC finalizer, like the (1 2 3) list in this example: 6> (with-objects ((o (new raii-class))
(p [finalize (list 1 2 3) prinl]))
(put-line "inside block"))
raii-class hello
inside block
(1 2 3)
raii-class goodbye
t
with-objects can't be used for defining function arguments, but it can refer to variables in scope; resource not defined in the block can be finalized: 11> (let ((x (new raii-class)))
(with-objects ((x x))
(put-line "inside-block")))
raii-class hello
inside-block
raii-class goodbye
t
Parameter passing has reference semantics so the smart-pointer style RAII use of C++ across function interfaces is not really applicable.We don't want to copy a struct argument when a function is called and be incrementing refcounts on things the struct's slots point to; that's just stupid.