4 ms·
"Why I hate garbage collected languages"
by yincrash 9y ago
"Why I hate garbage collected languages"
- adgasf 9y agoIt would be interesting to see a language that implements RAII but provides a GC as a fall-back.
- dmead 9y agoor just manual memory management with gc as a catchall..
- advisedwang 9y agoYou might like to have fun with the Boehm GC: http://www.hboehm.info/gc/ http://www.hboehm.info/gc/.
- akvadrako 9y agoPython uses reference counting with GC as a fall-back. RAII is basically reference counting with destructors, but it's not very useful if the object lifetimes are not easy to reason about. The optional GC (for circular references) greatly complicates things. [1] http://arctrix.com/nas/python/gc/ http://arctrix.com/nas/python/gc/
- zokier 9y agoRust went through that stage at one point. It had language-level support for GC, first by having @-pointers (e.g. @i32 would have been pointer to GC-managed int) and later when sigils were removed it had short-lived Gc<T> type. iirc GC support was finally completely removed during the crunch to 1.0. 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 http://words.steveklabnik.com/pointers-in-rust-a-guide for example (section "Managed pointers")
- kazinator 9y agoTXR Lisp supports a form of RAII: 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.
- Koshkin 9y agoGarbage collection sometimes offers a better efficiency than RAII - simply because it is "lazy" (vs. RAII which is always "eager" - often unnecessarily so).
- madballneek 9y agoCame here to post exactly this. Also, when the hell was this written?
- kazinator 9y agoTo be fair, there is some material there not related to GC; like about inconsistencies between built-in types and classes and whatnot. 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.