You have have heard of it (or them!)
You see, in that OS, individual windows (as GUI elements and "Operating System Objects") were not pointers, but Handles!
Every other OS-controlled object (Bitmaps, Brushes, Fonts, Device Contexts, etc.) were also Handles!
You see, Application Programmers (for normal applications, not Ring 0 device drivers) -- were never given direct pointer access to OS internal data structures!
Instead the OS handed out Handles for different OS-managed objects to application code that asked for them, allocated and managed the memory they used during their lifetime, and disposed of the memory so allocated when the application using them had completed or terminated.
Unix/Linux is similar -- except that the application programmer typically gets what's called a "File Handle" (because "everything's a file" under Unix/Linux...)
But generally speaking (and yes, there are exceptions like mmap() on Unix/Linux and ring-0 drivers on Windows) the application programmer never manages the memory allocation or disposal themselves, they never use direct pointers for these objects, they go through an OS proxy to that OS structure, that proxy is called a "handle", and it moves the proper responsibility for memory allocation/deallocation of the resource to the OS, away from the programmer.
Compare and contrast this with the use of handles (as proxies) and the concept of "Encapsulation" (from Object Oriented programming, but equally applicable here) in codebases where you have a central Senior developer who writes the central code in a language like C or C++, full of pointers, complex data structures, complex dynamic memory allocation/deallocation, etc., and you have regular developers who write code via the use of Handles around that central code, i.e., that central code does not expose pointers or direct memory -- instead it exposes an API or functions where regular programmers request handles, and subsequently pass the handles with additional API calls to the central codebase to gain functionality for whatever object or objects are represented by the handle.
(You can also compare this to obtaining a token/cookie from a web API, then passing that token/cookie on subsequent requests with different additional parameters to different endpoints on a single website's API to gain different functions related to the use of the back end object or objects that that token/cookie is related to...)
Also, I should point out that while replacing pointers with handles in code may make a programming a little bit slower, it also allows the handle allocation code to save/update a list of allocations. Hybrid code could replace pointer operations with handle allocation in a test/debug codebase, then replace it again with native pointer operations in a release codebase (faster, once all the bugs are worked out). A handle allocator is a powerful tool to check for memory allocation errors in code if it's programmed correctly... Allocate the same handle twice -- have your handle allocation code can check for that, and raise an immediate exception! Forget to free it at the end of use? Raise an exception for that! It's a great way to find bugs in pointer code!
Anyway, great article!
Related:
https://en.wikipedia.org/wiki/Encapsulation_(computer_progra...
https://en.wikipedia.org/wiki/Pointer_(computer_programming)
[–] lioeters 4 days ago
[–] peter_d_sherman 4 days ago
Well thank you very much! I appreciate the kind sentiment!
> Any problem in computer science can be solved with another level of indirection.
Indeed! I forgot to include this part when writing, it was "at the tip of my consciousness" but I couldn't recall that exact text exactly, so I didn't include it -- but you nailed it!:
>https://en.wikipedia.org/wiki/Fundamental_theorem_of_softwar...
>An entire operating system conceptualized as a hierarchy of handles.
It's quite the concept isn't it!
Incidentally, if you look at the Assembly compiler output of any "Object-Oriented" programming language (i.e., C++, ObjectPascal, etc.), you will notice that it is generating what looks like normal Assembly functions for non-Object-Oriented programming languages (C, Pascal, etc.), except that each function is getting passed an additional first parameter (typically as EAX on 32-bit x86 systems, RAX on 64-bit x86 systems), and that first parameter is actually a pointer to the "Object" in memory (pointer to a data structure that comprises the "Object" in memory -- since Assembler has no concept of higher-level programming language Objects!), but it's function is to allow a flat traditional function to operate on the data (and call associated related "object" functions (via another level of pointer indirection)) -- well, it's the same principle as a Handle (that of "Indirection": https://en.wikipedia.org/wiki/Indirection) in effect!
>It's about encapsulation, and designing the interface between objects.
Indeed!
>How handles are like functions, makes me think. A function is a form of indirection, and it can be seen as a handle or interface with defined types of inputs and outputs.
Exactly!
>And the useful of handles/proxies in testing. Yes, it solves the same question as "dependency injection" but in a more functional style.
You get "dependency injection" virtually for free!
>You pass in a handle with well-defined types of vaues, which can be treated the same way by functions whether the handle operates with a local test database or the actual production one. It's being able to have multiple implementations, or instances, with the same interface.
Yes! And (added bonus!) it decouples the handle using program (client) from the handle serving program (server!). That is, the code is not as strongly linked "bind/bound together" as code using raw pointers, and can be separated across boundaries (across processes on a single machine, across the internet on multiple machines) if the data is marshalled (fancy term for if the data of the variable which contains the integer value for the Handle is moved from point A to point B, wherever point A and B are, i.e., HTTP(S) request + JSON or XML or BSON or other structured data exchange format...)
Anyway, thank you again for your kind sentiments!
> Any problem in computer science can be solved with another level of indirection.
https://en.wikipedia.org/wiki/Fundamental_theorem_of_softwar...
An entire operating system conceptualized as a hierarchy of handles.
- Windows, GUI elements, "OS objects"
- Bitmaps, Brushes, Fonts, Device Contexts
- File system namespace - Objects as file descriptors - https://en.wikipedia.org/wiki/Everything_is_a_file
- Memory handles to manage allocation and freeing without directly handling pointers
- APIs, token/cookie, authenticated requests - and functions
It's about encapsulation, and designing the interface between objects.
How handles are like functions, makes me think. A function is a form of indirection, and it can be seen as a handle or interface with defined types of inputs and outputs.
And the useful of handles/proxies in testing. Yes, it solves the same question as "dependency injection" but in a more functional style. You pass in a handle with well-defined types of vaues, which can be treated the same way by functions whether the handle operates with a local test database or the actual production one. It's being able to have multiple implementations, or instances, with the same interface.