Post by Stephane LajoieThose parameters have to be the same (in type and amount) for every
component. This works well in WvMoniker because a "monikerable"
component is expected to be constructible from a string, but it's not
really different from IFactory + default constructor, only more flexible.
More flexibility is certainly good but the strong typing of ordinary
constructor parameters is really the biggest loss here. Note that
IDispatch is flexible and loose-typed too and nobody likes it for
exactly the same reasons...
That's what I don't like about the WvMoniker idea, I like just the
string... Just a string is good, because you can do stuff with it, like
put it in config file, send it over the network or even have a user type
it in without his head exploding (it isn't very nice, but you can live
with it, witness all these URIs people are getting thrown all the time).
When you start putting more, like a random IObject pointer (which is
only a hair better than a void*, in this context) and a void* (speaking
of the devil...), you open the door to all sorts of funny things and
context-dependent failures. You can't put this particular moniker string
in a config file anymore, because it doesn't return an object if you
don't pass it an object of exactly the right interface, as well as a
some other piece junk in the void*.
But the way XPLC is designed is to allow apenwarr to fulfill all his
crazy void*-filled fantasies without obstruction, so it will. We're also
all free to use it or not, which is, in the end, what is really important.
Post by Stephane LajoieThis is exactly what I would do most of the time also. Let's say I have
a module providing a set of GUI objects. I would get XPLC (mostly) out
of the way very early by asking for some kind of root object, and then
only use that object to create other objects (which can also be used to
xplc_ptr<IGui> gui = XPLC::create<IGui>(CID_gui);
xplc_ptr<IWindow> root = gui->createWindow("My app", ...);
xplc_ptr<IWindow> window = root->createSubwindow(0, 0, 200, 100, ...);
...
Almost all of these objects would be a specialized factory for other
related objects in the module. The xplc-cxx binding already does a fine
job of hiding IFactory and the IObject calls so this has all the
benefits of loose coupling while maintaining strong typing and looking
almost non-ugly.
This is just about the exact way I envisioned it. I don't want XPLC to
be a burden, and while you can certainly let it be a burden, you have to
want it to. The rules on interfaces are the only truly important rules,
how you stumbled on a pointer to that interface, that's a mere detail.
Note that Stéphane's example would have excellent ABI compatbility
caracteristics. He could create a IGui2 interface, rename the old IGui
to IGui1 (without changing it's methods, their meaning or its UUID),
have a "#define IGui IGui2" (for nicety), and one could either use the
IGui of the day through the typedef or if he doesn't use any feature of
the newer version, use IGui1 (maybe redefine IGui, for nicety again) so
that people that only have the older version can still use his software,
without requiring him to actually have the older software (as with glibc
or Qt, for example).
IGui2 could be derived from IGui1, if only a few methods were added
(like "createFunkyWindow"), which would allow software to directly pass
in IGui2 where IGui1 is wanted, in exchange for not being able to change
or remove methods, only adding them. Or IGui2 could *not* derive from
IGui1, but its implementation's getInterface could give a translation
wrapper when asked for IGui1. Or you could just send IGui1 to rot in the
pits of hell.
The point is, you *have the choice*. With C or C++, you hardly have any
choice at all, and there's usually no compatibility at all between two
versions (if you have software linked against Qt 3.0.3, it cannot use a
library containing a few extra widgets linked against Qt 2, or possibly
even Qt 3.0.1!).
Post by Stephane LajoieThe only remaining problem, in my mind, is the impossibility of doing
class Gui: public IGui {
virtual IWindow *createWindow(const char *title, ...) {
return new Window(title);
}
};
class Gui: public IGui {
virtual IWindow *createWindow(const char *title, ...) {
Window *ret = new GenericComponent<Window>;
ret->init(title, ...);
return ret;
}
};
The first syntax would be possible only if the component class was
deriving from GenericComponent instead of the other way around.
(not that I know how to make this work...)
Well, I've shown a way. This is a "mere" implementation detail, there's
nothing in XPLC's design that says that GenericComponent should even
exist, only its goal of ease of use. And the fact that you have to have
the two-phase init in a method like createWindow is rather silly (if you
made a C++ class that wouldn't have a default constructor, why should
you do so with XPLC?).
There's a few cool things that you get if you provide a default
constructor (particularly in a dynamic system like XPLC), but if you
don't need them, you don't need the default constructor either!
--
Pierre Phaneuf
http://advogato.org/person/pphaneuf/
"I am denial, guilt and fear -- and I control you"