Skip to main content

API design tips

For every larger application, you'll get to a point where you want to allow people to extend it, and then you have the problem of designing an API that the clients like.

Here are some things that a good API should always provide/have:

  • Consistency: The biggest, single most important point besides robustness. If your API is not consistent, it will feel like patchwork, and your clients won't like it. Just look at the Win32 API, where you immediately see that different functions use different styles. In contrast, see the .NET API, which was fully designed as a coherent API and provides a really nice programming environment. Write a design document up front, and stick to it, no matter the costs. For example, if you pass variable length arrays, stick with passing the count first, and then the array pointer, but don't mix it.

  • Robustness: Your API is the border guard between the evil client and your library. If your client can pass bad data through it, <em>it's entirely your fault!</em> Make sure you validate every single parameter passed to your API, and provide means to signal errors.

  • Documentation: Undocumented APIs are like non-existent APIs. Document each call, each parameter, and provide examples. Possibly the best documented API is the WinAPI/.NET, just take a look at the MSDN!

  • Error reporting: Provide a consistent way to signal errors. If you are designing a C API, have each function return a success/error code. For C++/Java/.NET, provide custom exception classes. Make sure that you have some function to format the error code and get a human-readable string out of it!

  • C-API tips: Pass structures instead of long parameter lists. Structures can be easily extended and only require a recompile from the client, while new parameters require the client to change their code. Use fixed-sized types: If you mean a 32-bit int, use a typedef exactly for that size. This enables your clients to do easy interop with your library, for example from C#. Make sure people with different compilers can link against your code. This means that all memory allocations that you are going to free must be done by your library, otherwise, clients with a different C-Runtime will get crashes. Don't use fancy compiler extensions, and make sure your code compiles with at least 3+ different compilers before shipping.

  • Easy start: Make it easy for the clients to get something running. If they need to create 5 objects first, and bind three of them together, you are doing something wrong. Provide convenience functions where possible: A very good example is the Qt library. In many places, a class expects a parameter of type QPointF (just a pair of floats), but also provides a function which takes two floats and creates the QPointF for you. Same for declarative structures. If your user has to describe something (for example, fill in 5 structures), don't force the user to allocate them dynamically but allow the user to use the simplest possible solution to get started quickly: Declaring it statically.

    Decls dec[] = {
      { "Module1", API_SomeOption },
      { "Module2", API_Debug | API_Log }

    The user can still decide to do it dynamically later on, as long as you provide init/shutdown hooks.

Music gem: Baba yetu

I've found a real music gem, and that in a place where you wouldn't suspect it: The opening menu theme in Civilization 4. The background track (which could be very well the main theme for a major blockbuster movie! And they have put it as the menu background!) is Baba Yetu by the composer Christopher Tin.

You've gotta hear this song. It's really incredible, perfectly sung by Stanford Talisman. Let's hope that this incredibly talented Christopher Tin will continue to provide songs like this, I'd buy an album full of this right away.

[Update] Until the album comes out, you can download this song for free on his page. Don't miss this chance!

std::tr1::shared_ptr tutorial

The C++ TR1 additions contain an extremely useful smart pointer: std::tr1::shared_ptr. Used properly, it allows creating efficient and safe C++ code without the risk of memory leaks. Point in case: I have a personal project with 10k + LoC without a single delete call.

How to get it, and what it is

std::tr1::shared_ptr is part of the TR1 additions to the C++ STL. With GCC, it is available either through #include <tr1/memory> (GCC 4.1) or #include <memory> (GCC 4.3), the latter form works also on Windows (with VS2008 SP1). If you want to be portable, try Boost, which uses the vendor-provided solution if possible and falls back to a custom one if no vendor solution was found. To use this, just include <boost/tr1/memory.hpp>

Basically, the shared pointer is a reference counted pointer. The references are counted using atomic instructions, so it is (mostly) thread-safe. Exception: If you pass the shared pointer by reference, and it is modified then by two threads, you'll run into problems, so copy it!

Usage examples

Let us take a look at several usage examples.

Deleting an array

An array can be deleted by providing a custom array deleter.

template <typename T>
class ArrayDeleter
    void operator () (T* d) const
        delete [] d;

int main ()
    // Usage
    std::tr1::shared_ptr<double> array (new double [256], ArrayDeleter<double> ());

or, if you have Boost and included <boost/smart_ptr.hpp> and you need a temporary array

boost::scoped_array<double> array (new double [256]);

scoped_array is noncopyable, which makes it perfect for local buffers.


It is possible to cast shared pointers using std::tr1::dynamic_pointer_cast and std::tr1::static_pointer_cast.

class Base

class Derived : public Base

int main ()
    std::tr1::shared_ptr<Base> base (new Derived ());

    // Static downcast
    std::tr1::shared_ptr<Derived> derived = std::tr1::static_pointer_cast<Derived> (base);

Custom reference counting

If your class has custom reference counting (COM, anyone?), you can still use shared pointers for it.

class CustomReferenceCounted
    CustomReferenceCounted (int* counter)
    : counter_ (counter)

    void Release ()

    int* counter_;

class CustomReferenceCountedDeleter
    void operator () (CustomReferenceCounted* r) const
        r->Release ();

        // So we don't leak memory in this example
        delete r;

int main()
    int counter = 1;
    std::tr1::shared_ptr<CustomReferenceCounter> crc (new CustomReferenceCounted (&counter), CustomReferenceCountedDeleter ());
    crc.reset ();
    std::cout << counter << std::endl;

Usage notes

There is a slight performance hit for the shared pointer copying, so you should pass the contained object by reference (preferably) or pointer unless the called code needs a copy of the pointer (for example, when inserting into a container).

Being reference-counted, you cannot use shared pointers for cyclic data structures directly. For this, you can fall back to weak_ptr, which does not prevent deleting the pointed-to object but allows promoting to a shared pointer if needed. For a big list of more tricks, take a look at the Boost shared_ptr documentation.

[Update] Changed the link to automatically point to the latest Boost documentation.

Convert a FAT32 partition to NTFS on XP Home

If you are using XP Home on a slightly older machine, your primary partition might be very well FAT32. At least on the two machines that I had with XP Home, FAT32 was the default. FAT32 is a pretty old file system, and lacks many useful features that NTFS brings (transparent compression, sparse files, you name it).

Converting is quite simple, and works without any 3rd party tools. Just run convert C: /FS:NTFS from the cmd line, answer yes twice, and on the next boot, Windows should convert the partition to NTFS. In case it hangs during bootup (just had this problem recently), shutdown, reboot, and select "last working version" -- which will skip calling convert and just boot up Windows normally.

WPF: Minimal WPF DataBinding example

WPF (Windows Presentation Foundation) is slated for becoming the next GUI toolkit for Windows (superseding Win32, MFC and Windows Forms). Unlike the others, WPF does not base on Win32 at all, but works on DirectX, providing features like fully vector-based rendering.

WPF has a lot of features, however, in this example we'll look at a particularly nice one: DataBinding. There is an interesting tutorial series from Microsoft about it, but we'll take a real quick and simple look at it here.


The idea behind data bindings is to separate the GUI from the data (I think I heard this before ;) ). In the case of WPF, properties are the ideal interface between GUI and objects. Each time a property is changed, an event will be raised, and the GUI gets notified about it. There is no need to connect it, as this works via reflection, the only code you have to write is the notification that a property has been changed.


In our example, we'll have a small data class like this:

class TestObject : INotifyPropertyChanged
    private string _name;

    public string Name
            return _name;

            if (_name == value) return;

            _name = value;

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));


Pretty simple. The GUI side is equally simple:

<Window x:Class="DataBindingTest.Window1"
    Title="Window1" SizeToContent="WidthAndHeight">
    <StackPanel Height="Auto">
        <Label Name="theLabel" Content="{Binding Name}" />
        <Button Content="Click me" Click="Button_Click" />
        <Button Content="Click me later" Click="Button_Click_1" />

By setting the Content property to {Binding Name}, we tell the GUI to watch the "Name" property of the object we will bind to it. The final step is exactly this, binding some object as the data source.

TestObject t = new TestObject ();
theLabel.DataContext = t; // This is the whole bind operation

That's it! We can now change the property directly, and the GUI will get updated automatically.

void Button_Click(object sender, RoutedEventArgs e)
    t.Name = "foo";