On 5 Jan 2004, Ted Gould wrote:
On Sun, 2004-01-04 at 12:50, Bryce Harrington wrote:
Can you explain about distinguishing between implementation and role? Is this like a class/instance type relationship or something else? I'm wondering if it would be conceptually simpler if this dualism could be handled in a different fashion than at the namespace level.
It's mostly to make things simpler in my mind (and hopefully others using the code). I'm looking at that there will be several types of implementations (scripts, internal, other languages (python, perl...)) and all of those will require some code and configuration to get them to work. I wanted to put those two things into their own little block and that desire is what implemenations came out of.
What it does for the user (user of code, not end user) is that they get a clear choice of what to look at for what they want to do. If they want to use extensions within the program, they only need to look at the extensions interface. If they want to build their own extension, all they need to look at is the implemenations interface.
So, in a nutshell, yes, it isn't a required seperation to make things work - but I think it does make things simpler for the users of the code (which hopefully there will be alot of) and it makes the object definitions a little bit cleaner for everything.
I'm open to other ideas though... this is just the one I thought of.
Ah... I think I think I sort of understand now. Feels like the seed of a good idea.
I'm tempted to think, though, that we don't need to have this idea show up at the namespace layer. It sort of sounds like you're going to want to have a root class with subclasses for each type of implementational interface, and that is probably best done in a uniform namespace.
So I think for the purposes of namespaces and the extension architecture perhaps we should just have everything live in Inkscape::Extension. The idea could be that you'd create a root class within this namespace named Extension, for instance, that establishes the common API that all of the different kinds of extensions would need to implement. Then you'd create a subclass of Extension for each different specialized kind of extension, with added interfaces unique to them, and then developers of plugins would subclass from there, as appropriate.
One thing we may need to consider is whether we need a way for the extension to publish its own API, versus if we can enforce all extensions of a given type to have exactly the same API. If we need an API publishing mechanism, I doubt we'd need anything as elaborate as CORBA or COM; it could simply expose a vtable as a hashmap of function pointers for its internal routines. Where this might turn up handy is if we want to allow extensions to be accessed from other extensions or scripts, to perform specialized activity. For example, I could imagine once a MathML extension exists, someone might put together a "solver" extension that manipulates the MathML extension to solve for particular variables.
Here's a rough idea for doing this. On Inkscape startup, the extension.xml file is loaded, to identify (potentially) registered extensions. When an extension first gains a reference we attempt to load it, erroring if it doesn't exist. The load process works as follows. First, the .so or .dll is loaded into memory. We run an identification routine to learn the plugin's information such as its name, version number, and type. This lets us update extension.xml and cast the Extension into the appropriate subclass. Now we know that we can use the routines in that subclasses' API.
Next, we run a registration routine, which lets the extension "publish" its API to Inkscape core. It does this by returning the metadata for each function, identifying its identification/name, calling parameters, return type, and a pointer to the function itself. Probably this will need to be done as an array of structs rather than a hashmap of objects, since we'll be limited by the dynamic linker.
Inkscape core takes this data structure and loads it into its internal extension registry, which would be implemented as a hashmap of id's to the routine itself.
So then in memory you'd end up with a data structure containing all of registered extensions; the loaded ones would have Extension objects attached, while the non-loaded ones would be NULL and loaded on demand. Each Extension object would have both the generic Extension API, plus (if converted into its correct subclass) its unique API if any. The Extension object would also hold another data structure of its "self-published" API, as id->routine mappings, that can be used by other extensions to communicate between themselves. We will need a way to provide arbitrary parameters and type checking for the routines, so that'll require some thought (perhaps via printf-like varargs, or else just pass all the params in as an void* array of (name,type,value) triplets).
Now, of course, if we wish to put off inter-extension invokations, then we can leave out this publishing mechanism, but I suspect we'll find this to be a major limitation quickly. An advantage of providing this publishing mechanism is that we won't need to rev the general extension API's very often, which will save major maintenance hassle.
Anyway, that's my off the cuff thinking. Should be useful as food for thought if nothing else. Might be useful to research how other drawing apps do this, to see if we can just borrow a design.
Bryce