Code: Select all
struct KeyboardDriver {
function(void) init;
function((int *scancode) -> bool) poll;
}
KeyboardDriver usb_kb_driver = {usb_kb_init, usb_kb_poll};
// define those functions
We can easily define something similar for ps/2, bluetooth, etc.
Now, imagine I get a fancy 'gaming' keyboard with LEDs whose colours can be changed. The driver for that keyboard exposes a function with a signature like
Code: Select all
void change_colour(int x, int y, int r, int g, int b)
I thought of a couple of possibilities, but none of them seem particularly good.
We could just add it as another member to the
Code: Select all
KeyboardDriver
Code: Select all
struct KeyboardDriver {
function(void) init;
function((int *scancode) -> bool) poll;
function((int x, int y, int r, int g, int b) -> void) change_colour;
}
As you add more and more optional extensions, that interface gets very bloated.
Another option is to have 'extensions'. So you have something like this:
Code: Select all
struct KeyboardDriver {
function((KbExtension) -> void*) load_extension;
function(void) init;
function((int *scancode) -> bool) poll;
}
enum KbExtension {
ChangeColour,
Explode,
...
}
------------------------------------------
void *pfn = kbd_drv.load_extension(ChangeColour);
if (pfn) {
function((int x, int y, int r, int g, int b) -> void) fn = cast()pfn;
//change the colour!
} else {
//colour changing not supported :(
}
Or we could bite the bullet, use OOP, and solve it with inheritance:
Code: Select all
interface KeyboardDriver {
function(void) init;
function((int *scancode) -> bool) poll;
}
interface ColourfulKeyboardDriver: KeyboardDriver {
function((int x, int y, int r, int g, int b) -> void) change_colour;
}
interface ExplodingKeyboardDriver: KeyboardDriver {
function(void) explode;
}
struct KinesisFreestyleRgbUsbDriver implements ColourfulKeyboardDriver {
//...
}
The problem with this is that it doesn't scale. Say I have one keyboard which explodes, another with colourful LEDs, and another that has both. Say my userspace app has separate codepaths for exploding keyboards, colourful keyboards, and boring ones. If I plug in the keyboard that has both, does it go along both codepaths? If not, which one?
Either you get into a nasty tangle of multiple inheritance, or you have a separate interface for each combination of possible extensions. Here, with only two extensions, you would need 4 interfaces: plain, colourful, exploding, and both.
If you had 5 extensions, you would 32 interfaces.
Is there something I'm missing? How have others solved this problem? Is it possible to usefully do ADT with a C FFI?