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
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.
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.