Saturday, June 16, 2012

Object Oriented C Reboot

As is normally the case I started something and then put it down and did lots of other things instead. In a rare bout of refocusing though I'm picking up the object oriented C (OCode) stuff again.

Previously I got very side tracked into setting up a perfect development environment as I would like to use at work. Something that would be compatible with automated build systems. Furthermore, I started trying to port the subversion externals pattern that I like to use for shared code to Git on GitHub - I quickly discovered that I'm still very much a Git newbie. This was not very lean of me...

So i'm rebooting. This time around I will focus on the task at hand which is to create a simple templating and/or preprocessing system for generating class and interface boiler plate for use in OpenTV applications which are exclusively written in C.

Let's start with a description of the pattern I currently use to implement classes. This part is simple and the boiler plate is not so bad.

The header:
The implementation:
Excuse any obvious errors, I just typed that out without trying to run or compile it, but i think you can get the idea - nicely encapsulated, right?

So that's all good. A little boiler plate in exposing opaque types and constructors/destructors but not so bad. The problems/challenges(/opportunities ;)) start when I try to extend this pattern with interfaces. Let's extend the example with that pattern.

The interface:
Now we can see some really obvious complexity. Just look at the length of it and it doesn't even do anything really. Immediately apparent is how much work it would be to add a new method to the interface.

  1. Add a new typedef for the method prototype
  2. Add a field to the interface structure
  3. Add an argument to the interface constructor
  4. Add a redirector method to allow the implementation to be called

It's fiddly work and potentially error prone (and this stuff can be hard to debug). The good news is that interfaces tend to be fairly stable once done as they don't contain business logic (although they may represent it I guess).

We're not finished though. The interface has to be implemented by our class for it to be useful.

Here's the new header for our class:

Notice the addition of a method to get an instance as an instance of MyInterface this is our casting convention.

Here's the new implementation of our class:

That wasn't so bad, we:

  1. Added a field to the class structure to store the interface instance
  2. Implemented the interface method
  3. Constructed an interface instance in the class constructor
  4. Destroyed the interface instance in the class destructor
  5. Added the method to implement our casting convention
Again it was fiddly though and remembering that we have to do these things in every class that implements the interface we are now exposed to following types of errors:
  • Memory leaks due to forgetting to destroy the interface
  • Strange affects from casting incorrectly in method implementations (doesn't seem likely until you remember that casts are a nightmare for hiding copy paste errors)

So let's review. We now have 3 quite complicated files that are quite hard to maintain. Particularly, changes in interfaces result in a large quantity of refactoring radiating out all over the place. Plus we have to be careful whenever we implement a new instance of an interface. And remember that this example only implements 1 interface method!

This is a barrier to using the pattern which I would like to overcome. Just writing it up took longer than I expected and I have to go out now so I guess there will be a part 2 where I actually get started on how I would like it to look and work :)

...
...
...

As an aside the work I have been doing to make OpenTV application generating and testing makefiles using make function implementations will likely be the subject of a future post. As will figuring out how to share code and resources across Git repositories/projects.

No comments:

Post a Comment