 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Atreides Guest
|
Posted: Thu Sep 22, 2005 7:05 pm Post subject: Plugins, Singletons, Need for a better design |
|
|
Hello,
I am developing an application which uses singletons heavily. My design
problem started after extending the application to allow plugins.
Basically, the following code returns a different pointer in the
application and the plugin:
DynamicObjectManager::instance()
The solution I had for this problem was to pass the pointer to the
DynamicObjectManager class to the plugins and plugins use the pointer
instead of "DynamicObjectManager::instance()". However I have recently
realised that this is not a general solution. (The problem case is too
complicated to write here.)
So the problem is that, I need a central container object in my class
to store common data such as some lists, some flags and so on. The
plugins also need access to this container object. But natrurally, I
don't want to pass the pointer of a central contrainer object to all
classes I create. This seriously makes the code crowded (not
complicated, but just crowded).
Is there a better design or design pattern which you would suggest for
applications sharing data with their plugins in a clean and a safe way.
Thanks,
Devrim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Fri Sep 23, 2005 2:29 pm Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
Atreides wrote:
| Quote: | Hello,
I am developing an application which uses singletons heavily. My design
problem started after extending the application to allow plugins.
Basically, the following code returns a different pointer in the
application and the plugin:
DynamicObjectManager::instance()
The solution I had for this problem was to pass the pointer to the
DynamicObjectManager class to the plugins and plugins use the pointer
instead of "DynamicObjectManager::instance()". However I have recently
realised that this is not a general solution. (The problem case is too
complicated to write here.)
So the problem is that, I need a central container object in my class
to store common data such as some lists, some flags and so on. The
plugins also need access to this container object. But natrurally, I
don't want to pass the pointer of a central contrainer object to all
classes I create. This seriously makes the code crowded (not
complicated, but just crowded).
Is there a better design or design pattern which you would suggest for
applications sharing data with their plugins in a clean and a safe way.
Thanks,
Devrim
|
Some application plugin architectures are no doubt better than others,
but the notion that any can be "safe" is unrealistic, to say the least.
Enabling third party plug-ins is by far the least safe way to let a
client extend an application's functionality. It is actually safer to
let clients add their changes to the application's source files
directly, than it is to let them add those features via a plug-in. At
least by incorporating new features into the program's source code, its
set of potential execution paths (and operating states) at runtime
remains bounded. The program, even after the customer's changes have
been added, remains completely testable (resources permitting).
An application with plugin support executes arbitrary code that needs
to be provided only at runtime. This kind of application has an
infinite number of potential execution paths and an equally infinite
number of operating states - in short the application can never be
completely tested. Consequently there can be no assurance that its
operation is either reliable or secure. In fact the quality and
security of this application lies completely outside the control of its
author. While some application programmers naively think an app with a
buggy plugin is just that, the reality is that an app with a buggy
plugin is a buggy app - their buggy app.
So in light of these rather unflattering observations, why would any
would any program support plug-ins at all? The reasons usually given
are bandwidth and conservation. Some plugins do have high bandwidth
needs. Running as part of the application process means no bandwidth
constraints when accessing application data. Implemented as a separate
process, a plugin would have bandwidth constraints. But the constraints
by themselves do not mean, as is often assumed, that plugins could not
be run in a separate process. It means only that the question to answer
is whether the constrained bandwidth is nonetheless adequate to meet
the plug-in's needs.
Conservation - that is, minimizing overhead - is the other reason often
given to justify plug-in support. Directly loaded plug-ins clearly do
not require the overhead of a standalone process. Equally as appealing,
a plug-in author needs to write the code only for the plugin itself and
is spared the chore of writing supporting code for a standalone
process. But once again, assumptions often replace investigation. The
program's author could provide a plug-in "shell" with the supporting
routines already written. The plugin author need not write any
additional code for a standalone process. The greater overhead of a
plugin as a separate program, often overlooks the fact that a plugin
could be run on demand. In fact, depending on usage patterns,
"standalone" plugins (actually "helper apps") may in fact may prove
less taxing on the machine's resources than a set of always loaded
plugins.
The most likely reason that programs support plug-ins, though, is
simply one of economics. Implementing a plug-in architecture is
inarguably less work than implementing a "helper app" architecture.
Given that the difference can be substantial, a plug-in architecture
often seems the only justifiable choice on a cost-basis. Ironically
though this cost savings rarely materializes. It is built on the
assumption that a successful plugin architecture is one for which no
plugins are ever written. And indeed this is (or should be considered)
the ideal outcome, but unfortunately one rarely achieved. Inevitably
one or move plugins are written. The problems with a plug-in
architecture do not really begin until it is actually in use. And its
problems (and its ongoing costs) never really end until it is no longer
being used.
To address the question being asked: yes, any design pattern not
involving loading and executing plugins in the application's process
space would be a better design pattern than one with direct execution
of plugins. It matters not which. Otherwise, the app should strive to
keep the plug-ins at arm's length if not further. Encapsulating the
plug-in in a virtual machine (Java) or a scripting language (Perl,
Python) would provided a good degree of separation. Adopting a
(preferably existing) component standard like COM or CORBA for plugins
would also help create this distance. Barring these possibilities, a
plugin API (or any API) should emphasize a functional interface and
minimize a data structure interface. Data structures defined by an API
makes evolution of that API difficult. Such data structures cannot be
changed (or even extended in some cases) without breaking existing
plugins. With functions as an interface, new routines can be added and
old ones deprecated. This flexibility makes it far easier for an API to
maintain backward compatibility while at the same time adding new
capabilities.
I would note thought that data structures can be useful when
implementing an API - just as long as the client is not exposed to
their structure. One common techique to manage multiple clients is to
pass each client an "opaque" pointer which the client passes back in
subsequent calls. This pointer points to a structure that maintains
various state information. But since the client has no knowledge or
dependence on its actual structure, the implementation is free to
change or replace it completely in future revisions.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Fri Sep 23, 2005 10:25 pm Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
Atreides wrote:
| Quote: | I am developing an application which uses singletons
heavily. My design problem started after extending the
application to allow plugins.
Basically, the following code returns a different pointer in
the application and the plugin:
DynamicObjectManager::instance()
|
I presume that by plugin, you mean an explicitly loaded dynamic
object, whose symbols should not be shared with other dynamicly
loaded objects.
The C++ standard says nothing about dynamic loading, and in
fact, the solutions differ greatly depending on the platform.
Thus, to get all the details, you'll probably have to ask the
question in a platform specific forum. In general, however, if
it is not the default, I think that you'll have to provide some
sort of information when linking the plugin, so that it knows to
look for symbol elsewhere, and not to include the module from
the library in the plug-in. Generally, I think you can do this
by putting the parts of the main application needed by the
plugin in a separate dynamic object, and when linking the
plugin, ask the linker to NOT incorporate this dynamic object
into the dynamic object it is building. I'm not sure of the
details, however, because on my platform, the default is such
that this sort of thing works automatically. (The default is
also such that if two plugins happen to use the same symbol
internally, the second plugin ends up using the instance from
the first. But of course, it's only a default.)
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Maxim Yegorushkin Guest
|
Posted: Fri Sep 23, 2005 10:26 pm Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
Atreides wrote:
| Quote: | Hello,
I am developing an application which uses singletons heavily. My design
problem started after extending the application to allow plugins.
Basically, the following code returns a different pointer in the
application and the plugin:
DynamicObjectManager::instance()
|
This is because plugins implement the function, while it must be
implemented by the plugin host only.
The solution to the problem is platform specific.
For Linux you create plugins as shared libraries with
DynamicObjectManager::instance() function undefined. When a plugin is
loaded by a host undefined reference to
DynamicObjectManager::instance() in plugin is resolved by dynamic
linker to host's one.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Marco Jez Guest
|
Posted: Sat Sep 24, 2005 2:14 am Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
| Quote: | Basically, the following code returns a different pointer in the
application and the plugin:
DynamicObjectManager::instance()
|
This is a problem that occurs on some operating systems. Where is the global
instance defined and created? If you use a static data member that is
initialized (once) in DynamicObjectManager::instance(), then simply move
that static variable into the function itself:
static DynamicObjectManager &instance()
{
static DynamicObjectManager inst;
return inst;
}
This should avoid the double initialization in both the linked library and
your application.
Cheers,
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jason Hise Guest
|
Posted: Sun Sep 25, 2005 1:43 pm Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
In the very near future I plan to release a C++ singleton library
(intended for eventual review and hopefully adoption by boost) which
among its feature set will support singletons that can be shared safely
between processes (this solves the problem of the dll and your main
program returning different instances). If you are interested please
email me and I will let you know when this becomes available, if not
you may want to look at the shmem library that I am using to implement
this functionality
([url]http://boost-consulting.com/vault/index.php?direction=0&order=&directory=Memory)[/url].
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Tue Sep 27, 2005 8:25 am Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
Maxim Yegorushkin wrote:
| Quote: | Atreides wrote:
I am developing an application which uses singletons
heavily. My design problem started after extending the
application to allow plugins.
Basically, the following code returns a different pointer in
the application and the plugin:
DynamicObjectManager::instance()
This is because plugins implement the function, while it must
be implemented by the plugin host only.
The solution to the problem is platform specific.
For Linux you create plugins as shared libraries with
DynamicObjectManager::instance() function undefined. When a
plugin is loaded by a host undefined reference to
DynamicObjectManager::instance() in plugin is resolved by
dynamic linker to host's one.
|
For Linux, if the DynamicObjectManager::instance() function is
actually used in the root program, the code will work with the
defaults. Which, of course, have a different set of problems;
both Windows and Unix offer a large number of options with
regards to dynamic objects, simply because one solution doesn't
fit all problems.
Generally speaking, there are two possible solutions to his
problem: ensure that DynamicObjectManager::instance() is present
in the main, and arrange for the dynamic objects to use this
instance, or put it in a dynamic object itself, and ensure that
the other dynamic objects use it as a dynamic object. I'm not
sure that the first option is available under Windows (although
it corresponds to the default behavior under Unix, *if* the
function is actually used in the main program), but the second
solution is definitly available under both systems, and is
probably preferrable in this case even under Unix.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
wizofaus@hotmail.com Guest
|
Posted: Thu Sep 29, 2005 2:58 pm Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
Maxim Yegorushkin wrote:
| Quote: | Atreides wrote:
Hello,
I am developing an application which uses singletons heavily. My design
problem started after extending the application to allow plugins.
Basically, the following code returns a different pointer in the
application and the plugin:
DynamicObjectManager::instance()
This is because plugins implement the function, while it must be
implemented by the plugin host only.
The solution to the problem is platform specific.
For Linux you create plugins as shared libraries with
DynamicObjectManager::instance() function undefined. When a plugin is
loaded by a host undefined reference to
DynamicObjectManager::instance() in plugin is resolved by dynamic
linker to host's one.
|
And under Windows, just make sure DynamicObjectManager::instance() is
implemented in a separate DLL that is linked to by both the
application, and any plug-ins (which I assume are also DLLs) using it.
Having said that, it's hard to think of why it would be a problem to
pass the pointer into the plugin via some sort of init() or load()
function.
I'm gathering that the app and the plugin both share code that expect
to be able to call the same DynamicObjectManager::instance() function -
but there's no reason that DynamicObjectManager::instance() could not
handle both the case of the pointer being supplied externally, and
returning a pointer to the current module's singleton instance.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Sat Oct 01, 2005 1:58 am Post subject: Re: Plugins, Singletons, Need for a better design |
|
|
wizof... (AT) hotmail (DOT) com wrote:
| Quote: | Maxim Yegorushkin wrote:
Atreides wrote:
I am developing an application which uses singletons
heavily. My design problem started after extending the
application to allow plugins.
Basically, the following code returns a different pointer
in the application and the plugin:
DynamicObjectManager::instance()
This is because plugins implement the function, while it
must be implemented by the plugin host only.
The solution to the problem is platform specific.
For Linux you create plugins as shared libraries with
DynamicObjectManager::instance() function undefined. When a
plugin is loaded by a host undefined reference to
DynamicObjectManager::instance() in plugin is resolved by
dynamic linker to host's one.
And under Windows, just make sure
DynamicObjectManager::instance() is implemented in a separate
DLL that is linked to by both the application, and any
plug-ins (which I assume are also DLLs) using it.
Having said that, it's hard to think of why it would be a
problem to pass the pointer into the plugin via some sort of
init() or load() function.
|
Probably not a problem, but if you have code which is to be
shared between the application and the plugin, you probably want
to put it into a separate dynamic object anyway, regardless of
the system. After all, you would expect that programmers
developing the plugins would want to test their code, and
they'll need the shared code to create their test harnesses.
--
James Kanze GABI Software mailto:james.kanze (AT) free (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|