DynObj - Dynamic Binary Runtime Plugin Objects Hosted by:
SourceForge.net Logo

DynObj Type IDs

To identify a DynObj interface across plugin boundaries, a combination of integer type IDs and/or string type names is used. The type ID is a 32-bit integer, so many type queries boil down to integer comparison.

Interfaces and implementation types

One can differentiate between:
  • Interface types
  • Class/implementation types
For a given interface, there can be any number of implementations.

Interfaces are fewer

The many-to-one relationship between implementations and interfaces indicate that type IDs for implementation will exist in greater number than those for interfaces. (It's a loy like a tree, where branches are few in numbers and leaves are plentiful.)

Interfaces are usually public

All implementations needs to know the details of the interface they implement. The users of an instantiated instance always access the type through the interface. This implies that interface type IDs have a grater need to be public than class type IDs.

One-to-one relationship

For some interfaces, it doesn't make that much sense to have multiple implementations. For example, for the builtin DynStr interface, it is enough with one class implementing the interface well. So there is a one-to-one relation here.

The implementation class is called DynStrC but we need not know about it as long as the DynStr interface does what it should do.

For a one-to-one interface, it is obvious which implementation to instantiate when an the app is requesting an object implementing it. So, this is non-ambigous:
  • DynStr *pds = do_new<DynStr>( "Initial string value" );
    // use it and later destroy it:
    if(pds) pds->doDestroy();
By default, when asked to create an object with a given interface, DynObj will delegate construction to the last library that has 'signed up' for instantiating this interface.

DynObj Type ID ranges

The 32-bit range of DynObj type ID:s are split into a number of sections:

Name #From ID #To ID Description
Built-in 0x00000000 0x003FF000 Public, built-in interface IDs
Public 0x00400000 0x7FFFF000 Public interface IDs
Library local IDs 0x80000000 0xEFFFF000 Private (app-specific) type IDs
Automatic IDs 0xF0000000 0xFFFFF000 Automatic type IDs

Type IDs in the two first ranges (below 0x7FFFF000) are globally unique. If two objects in a running program have the same type ID in this range, they are of identical type.

Builtin public type IDs

The first range is reserved for basic interfaces that are part of the builtin DynObj interface library (VObj, DynI, DynObj, NotifierI, ...).

Global interface library type IDs

The second range is for the globally shared interface library. If you have an interface in your application that you want 3rd parties to be able to implement, it is a candidate for this range.

They are allocated and managed from the administration section of this site. These interfaces can be used by any application. Interfaces with these IDs can be implemented by 3rd parties and used from any host application.

Application and library local type IDs

The third range is where type IDs for implementation classes are allocated. Usually, they are only used internally by a plugin library and need not be globally unique. They can be selected randomly in this range when asigning type IDs to implementation classes.

A type with an ID in this range is not changed when an application is restarted. However, there may be other applications or libraries that use its type ID for different types.

Automatic type IDs

The last range is used for types which don't care about having the same type ID whenever a program is restarted. They are allocated one-by-one as application starts and libraries are loaded.

Being allocated at run-time, these IDs have the property of being unique inside a running application, including all loaded DynObj libraries.

Type names (string type IDs)

Each type also has a corresponding string value. It is usually the source code name of the class. In some ways, it is used a little different than type integer IDs.

Type names can be used when querying for interfaces:
  • // %% DYNOBJ class(VObj)
    class DynI {
    • // Other method declarations...
      // Query for interface using string name
      virtual void* docall doQueryI( const char *type );
      // Rest of interface...
doQueryI above is the 'escape route' where by objects may expose sub-objects that are owned by reference (as opposite to those that are directly embedded in the memory of the compound object).

This doQueryI method can be overridden by derived types. It will find both interfaces to embedded objects and custom objects returned by calls to derived versions of doQueryI.

A C++ typed version of doQueryI() is also available. It does the same as do_cast except for using string type IDs and calling doQueryI for each DynI it encounters when traversing types:
  • template<class T, class U >
    T* do_cast_str<T>( U* pu );
One cannot make any life-span assumptions for objects returned by doQueryI. Using weak or shared references is required.

Interface query using type strings is slower than that of using type IDs. String comparisons are slower and it has to call out to derived versions of doQueryI one each type that is traversed in the operation.