From: scott (scottw_at_[hidden])
Date: 2004-02-29 22:53:16


Hi Mark,

You have introduced a third perspective - looks promising. Hope
I can keep track of all the differences and still contribute in some
useful manner.

> [mailto:boost-bounces_at_[hidden]]On Behalf Of Mark Blewett
>

<snip>

>
> class MyServant : public Servant
> {
> public:
> MyServant(Scheduler* scheduler) : Servant(scheduler) {}
> void do_fn(int x, int y) { std::cout << x << " " <<
> y << std::endl; }
> };
>

> class MyServant : public Servant
> {
> public:
> MyServant(Scheduler* scheduler) :
> Servant(scheduler), fn(this,
> &MyServant::do_fn) {}
> MethodProxy<MyServant, int, int> fn;
> private:
> void do_fn(int x, int y) { std::cout << x << " " <<
> y << std::endl; }
> };
>

<snip>

I understand the direction that both Matthew and yourself are heading. The
resulting interface for clients of your class, is concise. Fully bound
functions
are a nice packaging and there are plenty of precendents. There is one
design
constraint that this direction would impose on clients, that rules it out as
a solution for me. This doesnt necessarily interest you but just in case, I
will try to paint the picture as briefly as I can.

If active objects (i.e. classes deriving from Servant) communicate by
calling
methods defined in each other, then they have compile-time knowledge of each
other. Reasonable assumption I suppose. However, it follows that every
client of a
particular object, i.e. an active object that calls a member of another
active
object, is itself required to provide a specific interface. That being the
interface that the second object uses to respond.

Returning to the db server example; every client must derive from a common
class that defines all the members that the server might call. Perhaps like
this;

class DbServant : public Servant
{
public:
        DbServant(Scheduler* scheduler) :
        Servant(scheduler), fn(this,
                &DbServant::do_fn) {}
                MethodProxy<DbServant, int, int> fn;
private:
        void do_fn(int x, int y)
        { std::cout << x << " " << y << std::endl; }
};

class MyReadOnlyViewer : public DbServant
{
        // Run a status display repeated around
        // the factory
};

class MyViewerAndController : public DbServant
{
        // Run a window with controls
        // for modifying the data model
};

This (hopefully) seems like a reasonable circumstance. But as coded the
db_server would be calling methods defined in DbServant when what you
really want is different implementations for MyReadOnlyViewer and
MyViewerAndController. I assume that with some twiddling your technique
could accomodate these kind of requirements (given that you are still
reading and still interested).

Would the db_server also have a separate "db_interface" class?

Also, if this kind of interface class technique has any legs is it
also (potentially) dragging lots of implementation details along
with it? Can that be avoided? Should it be?

Cheers,
Scott