Handle in Programming
Introduction
We would see the term “handle” very frequently in programming languages such as C and C++, and this term can be confusing to the developers who have not implemented a handle previously.
In this blog post, I would like to discuss what handle is in programming.
Handle
What is a handle?
In computer programming, a handle is an abstract reference to a resource.
It is abstracted because there is no explicit convention about what exactly the true type name of the reference should be for a handle. It can be a pointer, a pointer to pointer, a reference to an object, a small object, an index value to an array, a string key value to to a hash map, etc., you name it. The exact true type name of the reference, which can be very long and complicated, is deliberately masked and simplified by having a usually short alias type name. There are accompanying functions defined in the same library to do a variety of things with the resource that the handle references.
Why do we create an alias handle type name?
Given there is a specific true type name for a handle, why do we create an alias handle type name? The motivation of having a shorter alias handle type name does not seem to be sufficient to justify, because there are always people, such as me, who like typing long variable type names. Instead, the major motivation of having an alias handle type name is because the handle type implementer does not want the user to know what exactly the true handle type name is.
The handle typename and the class of the object that the handle references are implementation details which are subject to change in the future. If the user knows what exactly the true handle type name is, the user might do some type specific or hacky operations which will become invalidated as the implementation of the resource class changes resulting in code break in the future. Especially for open source libraries, it is very straightforward to find the exact true type name of the handle, the declaration and the implementation of resource class. So instead of using the handle and the accompanying functions to access the object, the user can access the object in a different way that is compatible with the true handle type name. For example, suppose we have a class Foo
, the true type name of the handle foo_handle
is Foo*
, and the handle alias type name is FooHandle
. The class Foo
has an int
attribute which can be accessed by member function Foo::bar()
. The corresponding handle accompanying function to get the attribute is int get_bar(FooHandle foo_handle)
. In principle, the user should not know FooHandle
is Foo*
. Even if the user knows that the true handle type name of foo_handle
is Foo*
, the user should not access the attribute by foo_handle->get_bar()
, even though it compiles. Otherwise, later, when the foo_handle->get_bar()
implementation is used a million times in the program and the exact type name of FooHandle
is changed from Foo*
to Foo&
, the code will be broken and the user would have to fix the code in at least a million places.
When do we create an alias handle type name?
For any resouce class that we want to hide the details from the user, the reference to that class resource needs an alias handle type name. For the following types in a library whose resource will be created and used by user explicitly, they are almost 100% necessary to have an alias handle type name.
- The resource type whose type name consists of more than one type name. For example,
std::vector<int>
andstd::map<std::string, Foo>
. - The resource type whose declaration and definition have never been deliberatively exposed to the user.
How do we create an alias handle type name?
In C and C++, just do typedef
. For example, the CUDA stream handle type cudaStream_t
that CUDA programmers commonly use has a true type name of CUstream_st *
which is a pointer to a CUstream_st
class whose declaration and definition have never been publicly exposed.
1 | typedef CUstream_st * cudaStream_t |
References
Handle in Programming