APIs, Wrappers, and You

Member for

6 years 1 month
Submitted by SuperSayu on Tue, 08/12/2014 - 14:53

I am ridiculously busy and should probably be focusing on packing for my move instead of writing coding theory blog posts! However, this is something I feel strongly about.

I realized when thinking and tinkering with my SysAPI project (A longer discussion of which is due at some point) that APIs and API wrappers should be a native concept in programming languages. A wrapper, in this context, is a code-minimal set of defaults and an order of operations such that when you call a desired function (say CreateWindow()), all calls and parameters necessary for that function call are filled in with sane defaults. The result of a blank call to a wrapper function should be faultless, which is to say, while the result will have no user data attached to it, it will be free of errors. For example, most "Dialog box" functions work like this: if you request a dialog box but give it no parameters, a confusing blank popup is created.

Note that I said "order of operations." When you create a new window with, for example, the Windows Win32 API, you must call other related functions and store their results for later use in CreateWindow(), including in some cases creating objects and specifying their member values. Creating a wrapper--indeed calling the function in the first place--means knowing what needs to be done first as well as knowing what values are finally necessary. A wrapper, then, allows you to immediately jump to receiving a generic result, and any parameter you pass to the wrapper will modify that result.

The tipping point to where I thought this deserved a blog post was when I realized we already do this, but it isn't formalized. For example, let us look at color structures. Virtually every GUI library has a large set of default color constants built into the language--red, blue, etc--so that you can put human-readable color constants in the code instead of defining your own hex value, creating the object, etc. Where do these color constants reside? In C#, they are static members of the color class--in other words, they are variables attached to System.Drawing.Color, the type path, rather than variables attached to an instance of the object. This is a good and functional way to handle the concept, but does not mesh well with basic thinking about object-oriented programming. Static class members can only be called when there is no object--it is a property of the class, not a property of the object, even though the class defines the object.

In short, the concept of SysAPI in general is a takeoff of special files in unix; it is a thought experiment where the entire filesystem is build around API endpoints, which may supersede each other, inherit each other, or be (as we're discussing) a generic version of the API's intended functionality. So, for example, if your windowing system provides an API to create windows (let's say /Sys/GUI/Window for now), a wrapper for that Window API would create a blank window. If you install a different windowing system, it may replace the default /Sys/GUI/Window with a fully-compatible replacement, and the wrapper would provide essentially the same result under the new windowing system.

Similarly with colors; no matter what your API for colors looks like, if you only want default functionality (for example red), any API should be able to provide it, whether the API provides 8-bit color or 256-bit color with seven types of transparency and an optional dancing monkey. In this instance, *it is almost irrelevant what the underlying object provides* from the point of view of the programmer: red is red. If they later want to add dancing monkeys to their red text (or pixel or background color or whatever), they can add parameters to the basic wrapper for red color to enable it.

I think that wrappers will also help separate the API itself from various functions in the mind of the API designers, which is desperately needed in some cases. Existing programming languages suffer immensely from the idea that any given function call has only one possible set of default values, usually specified by leaving a function parameter blank. The more things that a function can do, the more information you have to put into a function call to differentiate between feature sets. Adding wrappers over functions allows you to specify a lot of information in a readable format; one of the substantial problems with function calls that have large parameter sets is that you can do little to make them easily readable. If instead you can take a particular function call and create a wrapper that fills out the parameters in a more verbose format, allowing the function call itself to be succinct and to the point (essentially closure, but I suppose simplified), then that can improve readability considerably.

There are other neat things about wrappers as a first-class concept. An easy one is that wrappers provide basic test cases to prove that two APIs are equivalent or compatible. If your windowing system provides "Window" and "Fullscreen" wrappers, but an update to the API breaks full-screen applications using defaults from a previous version, that will become immediately apparent.