tags:

views:

186

answers:

2

I have been working a year now as a software developer for a at the computer-vision department of a company. My main job is integration of third-party software into a framework, so i usually end up writing wrapper libraries because a lot of this third party software does not work the way we want it to work(not thread safe, pain in the a** to use etc.).

Normally i just wrap the whole library and guard the calls to the library with mutual exclusions(thread safety is somehow the major problem with most extern libraries). I really enjoy doing this, as it puts you into a lot of interesting situations and you get to see a lot of interesting code. However i often think that i am not doing it properly or that my implementation is not really good. I feel like i am lacking some sort of design knowledge on how to properly do stuff like that.

Basically i want to know if there are any good guidelines or hints about designing a proper 'API ontop of broken API', or if this is always bound to be quite hackish and ugly.

+5  A: 

I will quote an answer to another question on here the other day:

  1. Does your current method pass testing?
  2. Is it fast enough?

If yes, keep doing what you are doing.

As an alternative

Just ensure your new API encompasses both the intended functionality and the conventional or accidental functionality of the original. Also ensure it presents a 'fit-for-purpose' re-presentation. Take a peek at the C++ wrapping of C libraries in FOSS projects such as GTK/GTK for C++ (which just wraps the former).

If the API is broken, fix it and submit a patch ... get involved with the third-parties (I am assuming having access to the source means they won't mind this) ... You could re-write some of their API to be 'wrapping friendly' and suggest they merge some changes. If there is a problem, be the one to fix it.

Not much to it, just wrap A with B and ensure B does what A was supposed to, or is used for.

Aiden Bell
Thank you, that somehow boosted my confidence ;)I usually don't run into any speed or semantic problems but usually the code is just not as clean as i want it to be. but i guess there is no other way around it as i don't have the source of the third-party library.
tr9sh
+1  A: 

The only thing that I can add to Aiden's response is that you should also look to replace code that requires explicit initialization and termination with RAII techniques. When I've been faced with providing a façade over APIs, I always seem to run into a class that looks like:

struct ADVERTISER {
    /* a bunch of members here */
};

void adv_Initialize(ADVERTISER *adv, /* a bunch of arguments */);
void adv_DoStuff(ADVERTISER *adv);
void adv_Terminate(ADVERTISER *adv);

I've seen this wrapped in a C++ class in the following manner:

namespace wrapper {
  class Advertiser {
  public:
      Advertiser(): inited_(false) {}
      void initialize(/* a bunch of arguments */) {
        terminate();
        adv_Initialize(&adv_, ...);
        inited_ = true;
      }
      void doStuff() {
        validate();
        adv_DoStuff(&adv_);
      }
      void terminate() {
        if (inited_) {
            adv_Terminate(&adv_);
            inited_ = false;
        }
      }
  protected:
      void validate() {
        if (!inited_) {
            throw std::runtime_error("instance is not valid");
        }
      }
  private:
      ADVERTISER adv_;
      bool inited_;
  };
}

The problem is that the Advertiser class doesn't really make the API any easier to use or even cleaner IMHO. If you run into cases like this, then:

  1. Use a fully parameterized constructor to ensure that invalid instances do not exist
  2. Clean up all resources in the destructor
  3. Write a copy constructor and assignment operator if they make sense or make them private and don't implement them.

My goal is to make sure that whatever API I am presenting/creating/wrapping works with our existing coding style. I also try to bend the API into a more OO style than it may currently be in. I have seen a number of what I call object-oriented C like the one that I presented above. If you want to make them really fit into C++, then make then truly object-oriented and take advantage of what C++ gives you:

  • Be careful to manage any state variables.
  • If actions like copying don't make sense, then hide them.
  • If there is any possibility of leaking resources, then find some way to prevent it from happening (usually employing RAII helps).
  • Restrict the creation of instances using constructors to eliminate invalid instances and other edge cases.
D.Shawley
Thank you, i think this is some very good advice especially for me as i have a strong C background so i am fairly new to C++.
tr9sh
You are quite welcome. I spent a bunch of years doing C on embedded platforms before switching to C++ so I can definitely understand. I've found that it makes a huge difference if you make your wrappers fit into C++ better - this way you are gaining something by wrapping the other API.
D.Shawley