In this short post I try to argue that the usage of name “resource” to indicate a user-defined type following the RAII idiom is not entirely correct and a better one — “session” or similar — could be used instead. I do not try to say that this usage of name “resource” is just wrong; but I believe that using the alternative may make the understanding of some programming and design concepts easier.
I do not object to the name “resource” in general; I only object to using it for RAII-like types. Perhaps you have never called such types “resources”; in that case you will find my post simply unnecessary. But I did see people use it this way. For one instance, consider these two documents: “Design of Concept Libraries for C++”, “A Concept Design for the STL”.
What is a resource?
Let me try to provide a definition of a resource. In fact, I already stated it my other post on resource management. Note that this is not some widely accepted notion of “resource.” I just try to capture the characteristics that are essential for me to prove my point. It is based a bit on Wikipedia’s definition.
Namely, a resource is something that we are likely to run short, or out, of; and something that others are likely to compete with us for.
Examples of such resources include: a given file, memory, a mutex, a thread pool, a open file handler list, a video card. By the above definition the resource is not a lock (on a mutex): we cannot run short of locks, and we can create as many as we can, even on the same mutex.
How do we represent a resource?
Let’s pick the example of a mutex. Mutex needs to be accessible from a number of threads: i.e., from a number of locations. Thus it has to be either a global, or something similar to a global: a single object, references to which are passed around. A mutex cannot be copied. This is because the mutex m protects some data d, by storing the information whether m is locked (whether someone has already acquired m). If its value is copied, it is not clear which of the two mutexes protects d, neither is it clear if copying a locked mutex shall result in two locked mutexes.
The mutex cannot be moved either. This is because if it is a global, everyone expects it to be at the same location all the time. Even if mutex is not a global, it is referred to by references. If it is moved, the references would no longer refer to the mutex.
So, what is a lock, then? A lock is an object (likely a moveable one), whose existence (life-time) indicates that we (or the lock) owe the resource (a mutex) for this time. It is an indication of the ownership of the resource for a certain amount of time. Note this notion of time. A mutex is (likely) a global, it lasts as long as the program lasts; a lock lasts only for a certain (short) amount of time. The lock object indicates a session in which we play with the resource; and then the session expires.
Locks typically also cannot be copyable because this would indicate the two sessions where the same resource is accessed at the same time (although this is technically implementable and possible if, for a very rare situation, we need to implement a shared ownership). They can be moveable though, because it still guarantees only one session at a time.
Resources are globals?
I do not try to make a claim that all resources are really globals; but all the examples I can think of use some notion of a global; not necessarily in the C++ sense. It can be a singleton, or something similar. In a sense, the operating system itself is a sort of a global.
Consider one example of free store memory. It can be thought of as an implicit global memory allocator, accessible from everywhere; and operators new
and delete
the basic operations on the global allocator.
Does this view feel unsettling? That in the language that encourages value semantics to get closer to functional programming style all resources should be globals? Well, this is what C++ is. The value stored by the object is not the entirety of the object’s state but only the salient attributes that the object’s type exposes, as described in this analysis by John Lakos. std::vector
is a good example of this distinction. The value of a vector is determined by the values of elements it stores and the order of the elements. Vector also stores a capacity, which is related to memory management, but does not constitute the value of a vector. Creating copies of vectors renders other vectors with the same value (same values of elements an their order) but not necessarily with the same capacity. Capacity is part of vector’s state that is used for dealing with global resources, and has nothing to do with vector’s value.
Conclusion
The point I am trying to make is that name “resource” is not the best one to indicate types that implement RAII idiom for representing an ownership of a resource (like locks); because a resource (like mutex) is something that is a non-copyable, non-moveable global. A more accurate name would be “session” or “resource owner.” Such RAII-like objects are typically moveable and very rarely copyable.
>Such RAII-like objects are typically moveable but not copyable.
RAII objects can be copyable as well.
Hi Sarfaraz. Could you give us an example of a class type that implements a RAII idiom and is copyable?
OK, I figured it out. RAII can be used for other purposes than indicating resource ownership, like in the case of
std::vector
: in order to manage memory it probably uses RAII. Yet, it is copyable.Also for the case of resource ownership, we can implement a shared ownership model, which uses copyable types (although this is needed less frequently than many people think).
I updated the post, in order not to imply that you cannot copy RAII-like types. Thanks for pointing this out.
I’d say that a if RAII lock ‘captures’ a mutex, the ‘R’ is the mutex, not the lock (and I’d say a mutex is moveable but not copyable; moving a mutex does not cause a problem per se, as long as said mutex is not being held while someone else is moving its state). It’s the last ‘I’ that concerns the lock (the lock’s ‘Initialization’). Taken in that sense, the resource (the mutex) is indeed something we can run out of; a locks is RAII as it captures a mutex, but the resource is the mutex, while the lock is the resource-acquiring object. That being said, maybe I’m missing something from your argument…?
Hi Patrice, I believe we are talking about the same thing. I also tend to think that your way of explaining it is clearer than mine. Using your example, the point I was trying to make in this post is that thinking of a mutex as ‘RAII’ rather than ‘R’ is incorrect.