# RAII Pattern

To avoid resource management problems (acquisition and release), the RAII pattern is a must known of object-oriented programming. We tell you why.

If there is one problem that any developer encounters, it is resource management. The memory, the files, the network connections, the databases, the libraries to be initialized (openssl, opengl, ...), the mutexes, ... The list is long because indeed, any structure is a resource.

Anywhere in the code where we need a resource (its scope, which can be seen as a small universe bubble), the management of a resource comes down to the following three phases:

1. Acquisition: Did you obtain a valid resource?
2. Handling: does the resource remain valid?
3. The release: what happens if you do not release the resource?

Let's take a simple example of incrementing the value saved in a file. The following code, in language C, will perform the necessary operations:

• open the file,
• get a mutex,
• write the new value,
• release the mutex and close the descriptor.

For simplicity, I consider that the functions that read and write values are provided elsewhere and we will not dwell on them.

// Read / Write functions
void read(int fd, int * value) ;
void write(int fd, int value) ;

// Ressource handling
void increment(const char * filename)
{
int fd = open(filename, O_RDWR | O_CREAT, 0666);
flock(fd, LOCK_EX) ;
int value ;
write(fd, value + 1) ;
close(fd) ;
}

The problem in this version of the code is that no check is made on the validity of the resource (the file descriptor). What will happen if the file does not exist? If the mutex is not acquired? In the event of an error, the execution can exit the function without the file being closed...

You can believe me, it is always when you forget one of these checks that the case occurs. With luck, the quality department will tell you (and you can take your time to fix it), otherwise, it will be the support team because an unhappy customer has found a bug (and your time will be according to customer's patience).

# Second (better) Example

In this new version, still in language C, we will therefore carry out the necessary checks and be careful to free the resource in the event of a problem. This time, the functions return an error code (-1) when something goes wrong.

int read(int * fd, int * value) ;
int write(int * fd, int value) ;

int increment(const char * filename)
{
int fd = open(filename, O_RDWR | O_CREAT, 0666);
if (fd == -1) {
// Error while opening the file
return -1 ;
}

if (! flock(fd, LOCK_EX)) {
// Error while trying to acquire a lock
fclose(fd) ;
return -1 ;
}

int value ;
// Error while reading the file content
fclose(fd) ;
return -1 ;
}

if (! write(fd, value + 1)) {
// Error while writing the new value
flose(fd) ;
return -1 ;
}

if (! close(fd)) {
// Error while closing the file
return -1 ;
}

return 0 ;
}

What was clear is now complicated. From less than 10 lines, we go to about 30, the cyclomatic complexity is multiplied by 6. And from a resource management problem, we move to one of maintainability because for any change to the code will require checking the return codes, releasing the resource and returning an error code.

You can be sure someone will eventually change your code and forget a check or a release, it will be drama and hours of debugging ahead.

# The solution : RAII

Demonstrating once again the superiority of object-oriented programming, the RAII pattern solves these management problems in a very elegant way.

RAII is a programming idiom that comes to us from C ++ and whose goal is to guarantee that an acquired resource is valid and that its release will be automatically carried out when it is no longer in range (return, stop, exception, ...).

The concepts are indeed very simple and rather classic in OOP:

• encapsulate the resource in an object;
• manage the acquisition in the constructor;
• manage the release in the destructor;
• use exceptions to handle errors.

# Example in C++

Improving the previous example, we are now going to encapsulate the management of the file in a File class which will handle the opening in the constructor, the closing in the destructor and will provide methods for the other operations. All with exceptions to make it cleaner.

class File
{
private:
int fd ;

// Make File not copyable
File( const File& other );
File& operator=( const File& );

public:

File(std::string const & filename)
{
fd = open(filename.c_str(), O_RDWR | O_CREAT, 0666);
if (fd == -1) {
throw std::exception("Opening file failed") ;
}
}

~File()
{
close(fd) ;
// No check since one can not throw in destructor
}

void lock()
{
if (flock(fd, LOCK_EX) == -1) {
throw std::exception("Locking file failed") ;
}
}

void write(int value) { ... }
}

Thanks to this abstraction, the increment function becomes much simpler since it no longer needs to manage the various error cases but only to define a file and use its methods.

void increment(std::string const & filename)
{
File f(filename) ;
f.lock() ;
}

# Example in PHP

The implementation in PHP is similar and differs only by the syntax, the functions used are almost the same and the principle therefore does not change.

<?php
class File
{
private $fd ; public function __construct($filename)
{
$this->fd = fopen($filename, "rw") ;
if ($this->fd === false) { throw new Exception("Opening file failed") ; } } public function __destruct() { if (fclose($this->fd) === false) {
throw new Exception("Closing file failed") ;
}
}

public function lock()
{
if (! flock($this->fd, LOCK_EX)) { throw new Exception("Locking file failed") ; } } public function read() { ... } public function write($value) { ... }
}

function increment($filename) {$f = new File($filename) ;$f->lock() ;
$f->write($f->read() + 1) ;
}

# Which languages supports RAII?

This technique works with all languages supporting exceptions AND ensures that your destructors are called when execution leaves the scope of your objects. This is the case with real object languages such as C++ and PHP, of which we have just seen two examples.

For other languages, it's a bit more complicated. They often provide a finalize method called on when freeing but since they cannot guarantee that you will release your items as soon as you exit blocks, it won't help.

Some languages have chosen to cheat with a syntactic trick to fill this gap. With this particular syntax, you can define a method that will be called when the execution exits the corresponding particular block.

Other languages have outright snubbed the principle and considered it unnecessary. As in node.js where you will have to define your macros yourself and hope not to forget an error case.

# Example (dangerous) of false RAII

The problem with these methods, apart from the syntactic inconsistency, is that they are not guaranteed by the class which provides the resource but by the one which uses it.

The following example, in python illustrates the problem, the File class provides the same kind of method as before. The goodOne function shows the use of with. The problem is that nothing forces you to use this construct, as the evilOne function shows.

class File:

def __init__(self, filename):
self.fd = open(filename, "rw")

def __enter__(self):
return self

def __exit__(self, type, value, traceback):
self.fd.close()

def lock(self):
fcntl.flock(self.fd, LOCK_EX)

# ...

def write(self, value):
# ...

def goodOne(filename):
with File(filename) as f:

def evilOne(filename):
f = File(filename)
f.write(f.read() + 1)

So yes, you can answer me that we could delegate the opening of the file descriptor in the __enter__ function and add exceptions in the other methods if the descriptor is not available and therefore force the use of with:

class File:

def __init__(self, filename):
self.filename = filename
self.fd       = None

def __enter__(self):
self.fd = open(filename, "rw")
return self

def __exit__(self, type, value, traceback):
self.check()
self.fd.close()

def check(self):
if (self.fd is None):
raise Exception("File have not been correctly created")

def lock(self):
self.check()
fcntl.flock(self.fd, LOCK_EX)

self.check()
# ...

def write(self, value):
self.check()
# ...

But this solution is far from being as practical as a true RAII:

1. it complicates the File class by imposing a systematic check() call. Let one be forgotten or deleted and your will gain hours of debugging,
2. it only detects forgetting the with at runtime, so unless you have 100% code coverage by automatic testing, it will happen in production...

In short, you will understand, it remains only DIY to imitate the pros.

# And next

If your languages allow the use of this technique, I can only advise you to abuse it because it allows both to simplify the business codes but above all it makes them more secure by avoiding the problems of error management and release.