4 ms·
The with-* style function do not replace RAII except for the limited case of lexically scoped resources. Not all resources are scoped lexically -- e.g. file han
by lomnakkus 10y ago
The with-* style function do not replace RAII except for the limited case of lexically scoped resources. Not all resources are scoped lexically -- e.g. file handles you store in a map. What C++ programmers typically see as the most important guarantee is that RAII is prompt freeing -- that is, as soon as said example map goes out of its scope (or is freed by its owner), then those file handles will also be freed immediately.
Neither the gc-based nor with-* based solutions handle that.
- pjmlp 10y agoEven on C++ RAII requires a lexical scope at some point in the program. Somewhere in the whole workflow there must be a class allocated in the stack. You can have destructor like behavior in Lisp as well, just register a file handle cleanup action by giving a cleanup lambda when creating the map instance. The function that removes entries from the map will call the provided lambda.
- lomnakkus 10y agoI'm sure I must be missing something, but can you give a concrete example? Of course instances of classes (not "classes", as you say, classes are an entirely compile-time construct in C++) must be allocated, but I mean... there's still heap storage. You know, shared_ptr<T> and all that... What am I missing? > You can have destructor like behavior in Lisp as well, just register a file handle cleanup action by giving a cleanup lambda when creating the map instance. Well, except you don't know exactly when the map is going to get cleaned up...? And it could get reused across various sections of the program... Do you see what I'm talking about? EDIT: That, and if the map exists for the entire duration of the program, but it's really important that entries have prompt cleanup when removed... what then? (Btw, I do understand that in the general case with weak_ptr, shared_ptr, unique_ptr, etc. that things get decidedly less deterministic[1], but RAII is pretty well defined by scope or referenced-to-scope.) [1] Basically almost as unpredictable as a general purpose GC. I can't recall the paper title, but I'm sure there is a paper out there detailing this.
- kazinator 10y agoTXR Lisp: This is the TXR Lisp interactive listener of TXR 173. Use the :quit command or type Ctrl-D on empty line to exit. 1> (defstruct map nil (hash (hash :equal-based)) (:method lambda (me key) (gethash me.hash key)) (:method lambda-set (me key new-val) (let ((old-val (shift (gethash me.hash key) new-val))) (call-finalizers old-val) new-val)) (:fini (me) (dohash (key val me.hash) (call-finalizers key) (call-finalizers val)))) #<struct-type map> 2> (defstruct widget nil id (:static counter 0) (:init (me) (set me.id (inc me.counter))) (:fini (me) (put-line `widget @{me.id} says bye`))) #<struct-type widget> 3> (defvar map (new map)) map 4> (set [map "a"] (new widget)) #S(widget id 1) 5> (set [map "a"] (new widget)) widget 1 says bye #S(widget id 2) 6> (set [map "a"] (new widget)) widget 2 says bye #S(widget id 3) 7> (set [map "b"] (new widget)) #S(widget id 4) 8> (set [map "c"] (new widget)) #S(widget id 5) 9> (call-finalizers map) widget 3 says bye widget 4 says bye widget 5 says bye 10> (with-objects ((m (new map))) (set [m "x"] (new widget)) (set [m "y"] (new widget))) widget 6 says bye widget 7 says bye #S(widget id 7)
- kazinator 10y agoYou can see in my example that non-lexically scoped resources are involved also. Secondly, doing RAII into and out of a map container is largely a poor idea, and C++ programmers expend energy fighting it. The assignment operation and constructors and destructors of the map element all have lexical scopes somewhere.
- lomnakkus 10y ago> You can see in my example that non-lexically scoped resources are involved also. Please explain your example further then, because I don't see it. > Secondly, doing RAII into and out of a map container is largely a poor idea, and C++ programmers expend energy fighting it. Again, explain, please. Why is it a "poor idea"? Any links, at least? "Fighting it"... how, exactly? (It's been a while since I was a professional C++ programmer, but I don't really recognize this characterization.) > The assignment operation and constructors and destructors of the map element all have lexical scopes somewhere. Well, yes, but what about the MAP itself? It could easily be heap allocated. I'm sorry, I just don't see what you're on about.
- kazinator 10y agoThe map being heap allocated somewhere means this, in its most basic form: { map<whatever> *ptr = new map<whatever> ; // forgotten delete } If you don't want the heap allocated map to leak, and you want that management to be automated, you need some smart pointer type to reference it; map itself doesn't help. All RAII-driven management of heap resources is tied to some scope somewhere. Anything not tied to scoping has to be treated explicitly: try to calculate the lifetime and explicitly dispose of the resource.
- lomnakkus 10y agoAFAICT you're saying that RAII = RC. Am I correct in thinking that?