Wednesday, 24 January 2007

RAII

In a recent usenet thread regarding the practical benefits of garbage collection, a C++ user stated that having a GC makes it harder to deterministically free resources such as file handles, database connections and texture maps. I'd like to address this issue by explaining how garbage collected language retain all of the benefits of determinism when necessary whilst also allowing programmers to free themselves from the burden of explicit deallocation.

Firstly, let me describe what Resource Acquisition Is Initialisation (RAII) is. This technique involves wrapping the handle for an external resource in a class that provides a constructor to obtain the resource and a destructor to release it, something like this in in a C++ library:

class File {
Handle h;
File(string name) : h(new Handle(name)) {}
~File { h.close(); }
}

and something like this is the user's code to read a string from the file:

{
File file = new File("myfile.txt");
string text;
file.handle >> string;
return string;
}

The file is automatically close by the destructor of the "file"object when the scope ends. Moreover, if an exception is raised in the middle of the function then C++ still calls the destructor and closes the file as the exception propagates past the end of the scope, ensuring that we do not leak file handles.

Had we used a finalizer in a garbage collected language to close the file, the point at which the finalizer gets invoked and the file is closed is not known. Consequently, this is bad style.

However, the benefits of RAII can be obtained in F#. Essentially, you implement your own scope in a higher-order function. For example, to read a file you could use something like this in the library:

let read file k x =
let ch = open_in file in
try k x ch finally
close_in ch

To read a string, a user would then write:

read "myfile.txt" (fun () -> input_line) ()

Exactly this functionality is provided in the Idioms module of the F# standard library. The Idioms.using function can be used to create and destroy resources deterministically, giving all of the benefits of RAII.

So, there's one less reason to use C++...

Cheers,
Jon.

No comments: