Unification and Orthogonalisation: Part 2, Plugins and Bindings

Hi folks!

Part 2 of the series, there will be hopefully some more rational discussions. I want to review KDE’s plugin system.

There are currently three mainly used Plugn-technologies used by KDE projects:

  • KPluginFactory
  • Kross
  • QtScript

QtScript and Kross work similarly, both use qt-metacalls to allow scripts to access C++-objects. Thus it does only work for QObjects and only for q-properties, signals, slots and functions marked as scriptable. Additionally some data-types get automatically converted (containers, strings) and there is usually a fixed set of supported datatypes, e.g. QPainter etc. Both Kross and QtScript are easy to use, you can load script files and call functions using QVariants/QScriptValues and it reuses the QMetaObject-stuff. However, in my opinion there are a lot of downsides of those approaches:

  • You have to change the C++-code to allow interfacing with it (subclassing QScriptable, marking methods as scriptable etc.)
  • No easy way to expose functionality of non-QObjects
  • No plugins written in C++, which would be natural to have, although it would not be that hard to allow at least C-plugins in Kross
  • KDE application are usually programmed using object-orientation, even scripts are handled as objects, but inside the scripts the object-oriented architecture does not get continued, e.g. kwin-scripts are written in a procedural style, sometimes that is nice, but sometimes it would be nice if the script would follow the overall-architecture with plugin-classes or whatever

Some downsides are specific for QtScript:

  • It does not work with other languages than EcmaScript/JavaScript (no Ruby, Python, Perl…)
  • Sometimes QScriptable has to be subclassed thus making core-classes and plugin-functionality unnecassarily interdependent

Well, there is an alternative: KPluginLoader. Wasn’t that an uncool, unnecessarily complicated, old technology for C++-plugins? No, it is not. The idea is old (similar API had been included in KDE 2.0), but there are good reasons that it is still used although it has been indeed focused on C++: It is really flexible and it is really cool. Let me describe the idea: It is integrated into XDG-configuration-system, each plugin is described by a .desktop-file referencing a shared object file. A factory-object inside this shared object file is used to create instances of a plugin-class, which may subclass a class used to allow plugins inside the application (e.g. a Plasma::Applet, a KoShape or whatever). The factory is the reason for the flexibility of the architecture: There are specialised factories not simply allocating a C++-object but loading script-files, e.g. there are KRubyPluginFactory, KPythonPluginFactory and KPerlPluginFactory creating an object inside the scripting-language subclassing the plugin-class and exposing it to C++, but even more specialised classes libraries like plasma_appletscript_simple_javascript allowing a procedural interface. Those classes make arbitrary applications like Konqueror and KDevelop scriptable.

That is really cool, but there are limitations: Because the meta-object-system is not used there has to be a binding exposing the API of the application to the script. Of course it is nice that such bindings are orthogonal to the application itself and even non-QObjects can be accessed, but unfortunately it is currently complicated to add such bindings to an application. E.g. most bindings are using Smoke to access the libraries and the Smoke-Generator to generate the code for bindings, but you have to invoke it for each language, and the Python binding is using SIP. Hence it is comprehensible that many applications are using Kross or QtScript (though I do not see any good arguments for QtScript).

What could be done for unification? How could the dependencies between the plugin-functionality and the core-stuff be reduced? In my opinion it should be made easier to create a binding since that is currently the difficult task about scripting usin KPluginFactory, creating a plugin-class and invokin KPluginLoader to get plugins is not that complicated. A comprehensive set of cmake-macros would be cool, allowing to create bindings for Ruby, Python, Perl and QtScript using a single xml-file, it should detect pregenerated binding-files, invoke installed smoke-generators, convert it to SIP-information, and install it were the specific scripting-language expects the files. Creating such a XML-file would certainly not be more complicated than adding Q_SCRIPTABLE everywhere.

Maybe some of Plasma’s efforts to make scripting easy could be generalised to be usable everywhere in KDE-based projects (they did a good job ;)). Of course there should be a general purpose QtScriptPluginFactory (there is no such class, isn’t that strange?), but there are also some special features in Plasma, e.g. limitating the accessible API is a nice feature, it should be implemented in the plugin-factories, usually scripting-languages provide features to restrict importing of modules, accessing files etc., there should be a unified set of xdg-properties to specify what a script should be allowed to do. Using X-KDE-PluginKeyword to specify the script to load is also not very elegant, and passing arguments to plugins is also not perfectly implemented. Procedural scripting would be nice to have in many cases, too, e.g. there could be a KProceduralRubyPluginFactory automatically wrapping the functions in the scripting-file into a plugin-object in a generic way.

With such improvements we may get rid of QtScript and Kross, the architecture of some applications could be improved easily, and everybody could choose if he wants to use EcmaScript, QML, C++, Ruby, Python, Perl or whatever.

Disclaimer: There are always some people confusing thoughts and announcements, although the number of disclaimers does not seem to matter for them, there should be at least one: That is a review, some thoughts, no announcement for whatever. And I am familiar with the codebase.

Leave a Reply

XHTML: Use <blockquote cite="name"> for quotations, <pre lang="text    ∨ cpp-qt ∨ cpp ∨ bash ∨ other language"> for code, [latex] for formulas and <em> for em. Contact me if the comment does not get published, it may have accidentally been marked as spam.

Anti-Spam Quiz: