Shitty Code

Standard

While working on something, I realised something else. Well… that is how I go about life usually, but this time, a stroke of intelligent design struck me. Also, lately, my blogs have been all about friends and feelings pertaining to happiness and warmth between fellow humans. To restore the balance, I’d like to share a small hack I did. It is very cool in the sense that it uses an obscure concept of C programming.

Suppose that one has multiple sources of data. In words of MVC, suppose that you have multiple data Models. In C, such Models are represented as structures. For every type of Model, a structure can exist that provides a user accessible way to manipulate the data. For brevity, consider two SQL tables in a database. One containing the name and ID number of a person (call it contact) and the other containing height and weight (call it body) of that person.

Now, ways exist to make a C program connect to a data source to fetch data and one can cast that data into a particular structure. Let us assume that, after obtaining data from the tables, we have formatted that data into following structures.

struct contact {
  int id;
  char *name;
};

struct body {
  float height;
  float weight;
};

struct contact contacts[n]; // list of contacts of N number of people
struct body bodies[n]; // list of body type of N number of people

A problem arises when one tries to read or update these structures. Each structure needs a dedicated read and write functions because each structure is unique to itself. Like such:

void readContacts(struct contact *contacts) {
  int i = 0;
  int id;
  char *name;
  while(contacts[i] != null) {
    id = contacts[i].id;
    name = contacts[i].name;
    i++;
  }
  // do something with id and name
}

void readBody(struct body *bodies) {
  int i = 0;
  float h, w;
  while(bodies[i] != null) {
    h = bodies[i].height;
    w = bodies[i].weight;
    i++;
  }
  // do something with height and weight... redundant code. <- not cool.
}

But what if we have a generic type called LIST? In QtC++ and Android, we have ListViews that provide methods to manipulate such lists. We may have different “lists” for different types of Models but functions that manipulate them are same. That is what object orientation is all about… encapsulation and abstraction.

The problem statement hence can be laid down as such: We have lists of disparate data that we want to manipulate using a single abstract and generic data type LIST. This will let us define manipulation functions only once and use them for different lists… data encapsulation, that is to say.

Having understood the problem statement, we conclude that we need a “new” data type LIST. This data type must be able to store the data as well as provide methods to initialise, access and update the stored data. That is, we need a “constructor” to set the data in the list and a “getter” function to get the stored value.

struct _hidden {
 char *data;
 void(*constructor)(char *someData, struct _hidden *this);
 int(*size)(struct _hidden *this);
 char*(*getter)(struct _hidden *this);
};

As you can see, the above structure has a variable to hold the data and functions (pointers or rather pointer-to-implementation) to manipulate the data. C doesn’t have the concept of “this” pointers, but we need to keep a track of the current object that is being manipulated, struct _hidden *this is used to keep track of the current object.

Defining these functions are trivial:

void psuedoConstructor(char *data, struct _hidden *this) {
  this->data = data;
}
int size(struct _hidden *this) {return sizeof(this->data);}
char* getter(struct _hidden *this) {return this->data;}

The element of black magic that we now need is a way to set the function pointers defined in our structure to these manipulating functions. We must use such a method so that every time a new LIST object is created, these functions are available for them and that too, exclusively. This hallowed and dark piece of code is manifested as follows:

#define LIST(X) struct _hidden X = {.data = NULL, \
                                 .constructor = psuedoConstructor, \
                                 .size = size, \
                                 .getter = getter} // the crux of the magic

This syntax is used to initialise a structure with default values. If we use this in a macro we can now write a something like: LIST(L1). L1 automatically has all the member functions and can access the hidden data member of this structure. The actual structure (struct _hidden) is abstracted away.

We can now write an example:

#include <stdio.h>
#include <stdlib.h>
#include "shittycode.h" // the header file with all the black magic

struct contact {
 int id;
 char *name;
};

struct body {
 float h;
 double w;
};

struct contact contacts[3];
struct body bodies[3];

void makeModel1(){
 int i = 0;
 for(i = 0; i < 3; i++) {
 d1[i].a = i + 1;
 d1[i].name = "Code Ninja";
 }
}

void makeModel2(){
 int i = 0;
 for(i = 0; i < 3; i++) {
 d2[i].a = i + 2;
 d2[i].b = i * 0.235;
 }
}

int main() {
 LIST(l1); // generic data type list.
 LIST(l2);
 makeModel1(); // demo model... model can come from any where
 makeModel2(); // demo model... model can be any thing
 l1.constructor((char *)&d1, &l1); // must send a reference to self
 l2.constructor((char *)&d2, &l2);
 struct data1 *r1 = (struct data1 *)l1.getter(&l1);
 printf("%s, %d\n", r1[2].name, r1[1].a); // just checked random entries
 struct data2 *r2 = (struct data2 *)l2.getter(&l2);
 printf("%f, %f\n", r2[2].b, r2[1].a); // use loop to go through each entry
 return 0;
}

Clearly, L1 and L2 in the above code represent different lists having different data. We can still use same functions on both these objects without a conflict. Also, all the implementation of LIST is abstracted away from the user. They just need to call the appropriate functions related to this particular object.

We can of course have such implementation for anything we can imagine. For example: we can define a BUTTON to simulate a GUI button and associate an “onClick” event with it instead of a “getter”.

This little piece of black magic is available here.

 

Ninja.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s