If you are visiting this page, you are probably wondering why WFCO might be worth integrating into your project. This
C is primarily used as a procedural language, meaning that its code is supported through the invocation of procedures that operate on data. In a procedural language, data and the operations on them are seen as distinct entities. Many procedural languages provide for the creation of composite data types, and C is no exception: the struct keyword can be extremely flexible with this regard. It is very common to use the struct keyword to model entities with complex behavior. For the purposes of this document, these shall be informally referred to as objects.
This approach can become overwhelming when an object's state requires polymorphism (dynamic behavior intrinsically associated with the object). Consider struct sockaddr from UNIX's sys/socket.h header, for instance; the type (and therefore behavior) of the socket address is determined through an integral identifier as well as a variable-length buffer containing the address's parameters. This presents the problems that a) the object is very tightly coupled to its interface, and b) novel addressing schemes cannot be easily introduced. If a new method of connecting to a socket is introduced, it may require significant modification of assets outside of the project.
However, certain entities in the program environment do exhibit polymorphism and have done so for quite some time. A very early example is the file handle concept present in many operating systems: one does not need to know whether a file handle refers to a file, socket, or other I/O stream to read or write to it; all that matters is that file descriptors posses the state to effectively carry out these operations and that it somehow knows how to do so. A call to a system call like read() or write() on a UNIX system is abstract in the sense that the client code doesn't have to know what sort of stream a file descriptor refers to; these functions unify their behavior into a single interface.
Likewise, C programmers have occasionally explicitly specified polymorphism by utilizing function pointers to contain callbacks which specify an object's behavior. This design pattern has been occasionally used to facilitate this, with one potential manifestation looking like the following:
struct polymorphic;
typedef void (*polymorphic_doA_t)(struct polymorphic* this);
typedef void (*polymorphic_doB_t)(struct polymorphic* this, int argument);
struct polymorphic {
int state;
polymorphic_doA_t doA;
polymorphic_doB_t doB;
}
void polymorphic_doA(struct polymorphic* this);
void polymorphic_doB(struct polymorphic* this, int argument);
/* ... */
struct instance = { .state = 0,
.doA = polymorphic_doA,
.doB = polymorphic_doB
};
... where a call to the behavior (or method) doA is facilitated by invoking instance.doA(&instance). This conceivably allows for the structure polymorphic to provide any behavior, and expectations of operations on polymorphic are enforced by contract in this model. This means that struct polymorphic is a class: it has a well-defined interface and state. instance, not surprisingly, is known as an instance of class struct polymorphic or as an object proper of that type (herein, simply object). Curiously, it is also possible to derive a subclass of struct polymorphic:
struct derived;
typedef int (*derived_doC_t)(struct derived* this);
struct derived {
struct polymorphic super;
int newState;
derived_doC_t doC;
};
void derived_doB(struct polymorphic* this, int argument);
int derived_doC(struct derived* this);
/* ... */
struct instance = {
.super = {
.state = 0,
.doA = polymorphic_doA,
.doB = derived_doB },
.newState = 1,
.doC = derived_doC
};
This code has extended struct polymorphic in several important ways. First, it has created a new data structure which inherits all of the states and some of the behaviors of struct polymorphic; we can treat struct derived as though it were struct polymorphic because its base address incidental corresponds to that of a valid struct polymorphic. For all intents and purposes, any struct derived is a struct polymorphic.
Secondly, our struct derived instance has overridden the method doB, such that it has different behavior from its superclass, struct polymorphic. That it should be able to do so shouldn't be surprising; after all, the code is polymorphic. However, the introduction of the doC and the new state newState is extremely flexible, as it allows to carry state that a client of struct polymorphic doesn't necessarily need to know about, but would be useful on instances of struct derived.
This is not the only way of authoring a class in C; indeed, WFCO uses virtual tables instead. It should, however, become apparent that this method of authoring classes is extremely verbose. The C++ programming language, for instance, started as a preprocessor to compile specially written code into C sources. Over time, this evolved into its own language, and although the C++ standards committee has put in a great deal of effort to make C++ (mostly) a superset of C, the two are not always compatible. For instance, C++ can invoke C functions and deal with C structs, but C cannot easily operate on C++'s classes without additional glue code. After diverging calling conventions and name mangling, it is often not the case that a C compiler has any idea how to do this, so operating on C++ objects in C is either done through wrapping the C++ code or by sacrificing functionality.
The original author of WFCO has been faced with this problem, and largely chooses to write the most foundational parts of the library in C (offering additional bindings to C++ as necessary). This project originally arose out of another, Wheefun DOS Multimedia Framework, which targets MS DOS and similar operating systems: he wanted client code to be able to use C++ easily, but did not want to sacrafice support for C to do it. Additionally, the need to target other languages might arise as well. Because others might possess a similar need, it was decided early on that the code written to facilitate this should be shared with others. It is provided in the hope that other programmers will find it useful.
WFCO aims to provide the following functionality:
The following functionality is not intended to be provided at this time: