Inside niven: Dynamic class loading
Today, we take a look at niven’s class loader, which is responsible for dynamic instancing of classes from plugins and packages, and is likely to become a core component of the serialization system.
The class loader
The class loader is a component that is tightly coupled with the RTTI system. I forgot to say last time that the RTTI system with class instancing has a drawback, you need a default constructor for each class (i.e. className ()
) - just occurred to me when a class that used to work refused to compile due to a missing default constructor. This limitation is not as bad as it might sound at first, as most “interesting” classes don’t have parameters in the classes constructor, and classes that are instanced during serialization have to init from the source archive and not the constructor anyway. The class loader supports two ways of loading classes:
- Loading from Packages: A package is a simple DLL file that exports the
getClass
-Functions, as described last time. Packages don’t need to be initialized before use. A good example of a package file is the application itself. The package contains in this case the classes that contain the application logic. Other packages might include different resource loaders, which could be loaded during runtime (think of shader generators, for example). The package loader is not working yet, but this is only a matter of time, as the second loader works, which supports a super-set of the features needed for package loading. - Loading from Plugins: A plugin is a DLL file that exports all the same functions as a package, and special plugin-handling functions (init, shutdown and a plugin-info function). Special care has to be taken so these function are always called before using the plugin, and that they are only called once. For the class loader though, it is no difference if it’s invoked with a Plugin or a Package, as it assumes that in case of a plugin it has been already properly initialized. The load call itself is the same as in the package case.
There might be more ways sometime, as it is possible to create custom script-driven objects that are loaded by the class loader (objects that contain code that is executed during run-time) The class loader might even be extended for loading a special kind of classes into a VM. At the moment, the Package & Plugin loading is most important though, and other loaders are not planned for the nearest future.
Type safety
The class loader is completely type-safe: When loading a class, the loader checks if the class is derived from the one it should be assigned to. Usually, you don’t want to create an instance of a class you know, but rather of unknown classes. Example: The render driver is located in a plugin, and the name of the class varies, the only thing that remains the same is the interface the class implements, namely iRenderer
. To load a class, you would use now loadClass <iRenderer> ("name of the class", the_plugin)
. This is able to load any renderer, just as long as it’s derived from iRenderer
- you just specify the name and the plugin/package where to find it. The engine takes care of finding it, checking whether it is a valid derivate of iRenderer
and if so, instancing it. This checking turns out to be rather simple, as the loader is working on the RTTI classes anyway. So much for today, when I get into serialization, I’ll revisit the current class instancing mechanism, as it’ll probably need some tweaking. Anyway, at the moment, things are looking really good, with those core services running, I have really good hope the serialization stuff won’t block me too long. I’ll take another look at the window handler then, splitting it up (the window creation is currently bound to the input, which is altogether bound to the renderer - something I want to break up).