Hacker News new | comments | show | ask | jobs | submit login




What RAII and Ruby's block statement lack here are automatically doing the reversing of functionality.

Few languages have any procedural way to do that.

If Ruby had some way to state "the opposite of opening a file is closing a file" and then use it everywhere, we could do that. The block-syntax open is nearly that, but not quite. You'd need to have no non-block-scope way to use the resource for it to work.

RAII would also give the same benefit, if there were no non-RAII way to declare the resource.


Hmm. I don't agree with this conclusion. Take for instance a file class in C++ which opens the file descriptor in the constructor and closes it in the destructor. Now, for any instance of this class, it is impossible for the open fd to outlive the instance!. That is an as strong guarantee as I need! Now, if I leak the instance the fd will leak too, but that is more an issue of manual lifecycle management if you ask me.

This very significant property is what makes me love RAII. I don't count C#'s using-statement and/or rubys block statement as RAII since it relies on useage patterns. C++'s automatic destruction of graphs of objects also makes it outshine all other methodologies, and the guaranteed destruction is the key here.


RAII is a usage pattern: You must stack-allocate an object or wrap it in a suitable smart pointer. It's just as easy to do things differently as it is with Ruby's blocks or C#'s using statement. The reason it has a name is because it is a pattern that's talked about so much exactly because following the pattern is so intrinsic to modern C++ programming.

Once you're passing a block to a method like this in Ruby, the execution of the cleanup code is just as guaranteed as it is in C++.


I don't agree completely. As I said, you cannot leak the fd without leaking the memory of the object. This means that in C++ you get the correct behavior as long as you take care of the lifecycle of your objects correctly. You don't need to do stack allocation or smart pointers as long as you de-allocate the object when your are done with it. So the lifetime of the fd is tightly bound to the lifetime of the wrapper instance. If you stack allocate without deallocation you have a bug _anyway_ in your C++ program, thus I would like to argue that it is a problem of manual lifecycle management, not a flaw in the RAII implementation.

You do however have a point when you say that you can miss deallocation and that is just as easy as forgetting to put a variable in a block. In an ideal world I would like to be able to decouple de-allocation time from destruction time, as someone mentioned above they are completely orthagonal issues. If this would be possible, one could guarantee the destructor callback, but defer deallocation until later. This would probably give leeway to more effective memory allocation patterns while keeping RAII alive.

And another thing about blocks: how do you deal with trees and graphs of objects? That is not trivial when using blocks. You can get around it, but continuing that way would most likely lead you to something like Haskells monads (the "programmable semicolon" aspect of them).


You'd need to have no non-block-scope way to use the resource for it to work.

You can already do that, just `return unless block_given?`. In principle I don't see why you'd want to non block version anyway but maybe there's some use case where that is valid.


IIRC, Common Lisp has an UNWIND-PROTECT operator for that. It works even if exceptions are thrown, and it is the reason Common Lisp (as opposed to Scheme) has no continuations.


Python's context managers have that; define the two sides of the functionality in __enter__()/__exit__(), and voila.

C#'s IDIsposable has this, too.

So do other languages. It's really not that unusual a pattern.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: