Interface Records

An interface record holds function pointers as its fields. Basically an entire interface is specified through function pointers in the struct rather than through a header file and called directly.

Since specific functions have to be placed inside the fields there are opportunities here:

  • Functions a client is not going to be allowed to call can be left nil.
  • An old client may get different functions that include workarounds or upgrade paths.
  • Functions can also be "wrapped." This is similar to Lisp's defadvice or Python decorators where a normal function call is wrapped within some custom behavior before and after the underlying call.
typedef struct _thingi {
    int version;
    void (*boop)(thing_t*, const char*);
} thing_i;

c.boop(t, "blobcat");

The interface is itself a versioned record which can rely on version tags or simple append-only design.

Our Machinery relied on an append-only design for plugins. Old plugins can only call older endpoints in the interface while newer ones have access to the longer interface. Since this record only holds function pointers there is no issue with the older versions being smaller.

LV2 relies on a manifest file to define what capabilities a plugin has. Each capability is then an interface record supplied once the host knows it should provide one. Plugins then use the interface records to coordinate how the host should communicate with them again to synthesize sound.