Sign in to follow this  
speciesUnknown

This meets all my requirements, now make it non dependent on exceptions

Recommended Posts

For a while Ive been trying to come up with the "perfect" implementation of polymorphic event handling. This example demonstrates all the behaviour I want, however, it uses exceptions in what can only be described as an abusive way. Those who are easily upset need not continue.
class IMessageHandler;

class Message
{
    public:
        virtual void evil()=0;
};

class IMessageHandler
{
    public:
       virtual bool handleMessage( boost::shared_ptr<Message> msg )=0;

};

class BadNews : public Message
{
    public:
        BadNews(){}
        virtual void evil(){ throw (BadNews()); }
};

class TabloidNews : public Message
{
    public:
        TabloidNews(){}
        virtual void evil(){ throw (TabloidNews()); }
};

class GoodNews: public Message
{
    public:
        GoodNews(){}
        virtual void evil(){ throw (GoodNews()); }
};
    
class NewsMessageHandler : public IMessageHandler
{
    public:
    
        virtual bool handleMessage( boost::shared_ptr<Message> msg )
        {
            
            try
            {
                msg->evil();
            }
			catch(GoodNews& goodNews)
			{
			    cout<<"Got some good news"<<endl;
			}
			catch(BadNews& badNews)
			{
			    cout<<"Got some bad news"<<endl;
			}
            catch(Message& message)
            {
                cout<<"This isnt news"<<endl;
            }
            catch(...)
            {
                return false;
            }
            return true;
        }
};

int main()
{
    boost::shared_ptr<NewsMessageHandler> h( new NewsMessageHandler() );
    
    boost::shared_ptr<Message> b ( new BadNews() );
    boost::shared_ptr<Message> g ( new GoodNews() );    
    boost::shared_ptr<Message> t ( new TabloidNews() );   
    
    h->handleMessage(b);
    h->handleMessage(g);
    h->handleMessage(t);
}



Any implementation of this system MUST satisfy these requirements: 1) Everything is a shared ptr. I dont want to be passing around by value or reference and I dont want the risk of leaks. 2) I must be able to have an inheritance tree of messages. For example, as demonstrated, I have class Message, and I subclass this into GoodNews, BadNews, and TabloidNews. Flat lists of message type, each corresponding to an enum, are undesireable. 3) My handlers must not be dependent on any list of all message types. Each handler selectively implements only the types it wants. 4) The messages themselves are not dependent on any kind of message handler; they have no such concept. 5) I can have an inheritance tree of message handlers. Some message handlers might check for types lower down the heirarchy, and delegate events to more specialised event handlers. So, I might subclass BadNews into various types of bad news, but have a handler which only checks for a BadNews and delegates. I also want to have lists of message handlers, deriving from IMessageHandler, and iterate it and send events to them all. Is there a perfect implementation which demonstrates the same behaviour as above, but without using exceptions abusively? I've looked at using visitors, but the use of shared_ptr causes problems here. When being visited, a message doesnt know its shared_ptr. I've looked at RTTI but then I cant tell if a message is derived from some base or not, without checking for all known derived classes of that base.

Share this post


Link to post
Share on other sites
Quote:
Original post by speciesUnknown
I've looked at using visitors, but the use of shared_ptr causes problems here. When being visited, a message doesnt know its shared_ptr.


class Message : boost::enable_shared_from_this<Message>
{
...
};

class BadMessage : Message
{
public:
boost::shared_ptr<BadMessage> shared_from_this() const { return boost::static_pointer_cast<BadMessage>(Message::shared_from_this()); }
...
};


Alternatively, with CRTP, and closer to const correct:
class Message : boost::enable_shared_from_this<Message>
{
...
};

template < typename SelfT, typename BaseT > class inherit_shared_from_this : public BaseT {
public:
boost::shared_ptr<SelfT> shared_from_this() { return boost::static_pointer_cast<SelfT>( BaseT::shared_from_this() ); }
boost::shared_ptr<const SelfT> shared_from_this() const { return boost::static_pointer_cast<const SelfT>( BaseT::shared_from_this() ); }
};

class BadMessage : inherit_shared_from_this< BadMessage, Message >
{
public:
...
};




Quote:
I've looked at RTTI but then I cant tell if a message is derived from some base or not, without checking for all known derived classes of that base.

This you can do with dynamic_cast -- or dynamic_pointer_cast for shared_ptr.

boost::shared_ptr<Message> foo = ...;
boost::shared_ptr<BadNews> bad = boost::dynamic_pointer_cast<BadNews>(foo);
if ( bad ) {
// foo points to a BadNews or something derived from BadNews
} else {
// foo was null or not a BadNews
}


Share this post


Link to post
Share on other sites
I decided to go with the dynamic_ptr_cast method. Tested as working nicely


#include "boost/pointer_cast.hpp"

using boost::shared_ptr;
using boost::dynamic_pointer_cast;


class IMessageHandler;

class Message
{
public:
virtual ~Message(){}
};

class IMessageHandler
{
public:
virtual bool handleMessage( shared_ptr<Message> msg )=0;
};

class BadNews : public Message{};

class YouWereAdopted : public BadNews{};


class GoodNews: public Message{};

class YouWonTheLottery : public GoodNews{};

class TabloidNews : public Message
{
public:

};
class InaneDrivel : public TabloidNews{};

class NewsMessageHandler : public IMessageHandler
{
public:

virtual bool handleMessage( shared_ptr<Message> msg )
{
shared_ptr<BadNews> bad;
shared_ptr<GoodNews> good;
shared_ptr<TabloidNews> tabloid;

if( bad = dynamic_pointer_cast<BadNews>(msg) )
{
cout<<"Sorry, you got some bad news"<<endl;
return true;
}
else if( tabloid = dynamic_pointer_cast<TabloidNews>(msg) )
{
cout<<"Sorry, you got some tabloid news"<<endl;
return true;
}
else if( good = dynamic_pointer_cast<GoodNews>(msg) )
{
cout<<"You got some good news"<<endl;
return true;
}
return false;
}
};

int main()
{
shared_ptr<NewsMessageHandler> h( new NewsMessageHandler() );

shared_ptr<Message> b ( new BadNews() );
shared_ptr<Message> g ( new GoodNews() );
shared_ptr<Message> t ( new TabloidNews() );

shared_ptr<Message> lottery ( new YouWonTheLottery() );
shared_ptr<Message> adopted ( new YouWereAdopted() );
shared_ptr<Message> drivel ( new InaneDrivel() );

h->handleMessage(b);
h->handleMessage(g);
h->handleMessage(t);

h->handleMessage(adopted);
h->handleMessage(lottery);
h->handleMessage(drivel);
}




As always MaulingMonkey is the go to guy for awkward solutions to problems with an awkward langauge :)

Share this post


Link to post
Share on other sites
I don't understand your restriction on *having* to pass around shared pointers. Why are references undesirable? Are you dispatching the messages asynchronously or something?

If your message manager is just adding messages to a queue for later processing, but then you actually dispatch them to the handlers synchronously, then sure store shared_ptr<>s in the queue, but right before you're about to dispatch it, just do


foreach (MessageHandler* handler in handlers)
handler->handle(*message);



by reference.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
I don't understand your restriction on *having* to pass around shared pointers. Why are references undesirable? Are you dispatching the messages asynchronously or something?

If your message manager is just adding messages to a queue for later processing, but then you actually dispatch them to the handlers synchronously, then sure store shared_ptr<>s in the queue, but right before you're about to dispatch it, just do

*** Source Snippet Removed ***

by reference.


THe reason I want to do this is because I want to route events high on the inheritance tree by their base types first. Note how YouWereAdopted is a derived class of BadNews, and yet I can route all my BadNews by testing for derivation from BadNews. I could have one handler for all my BadNews, one for all my GoodNews, and one for all my TabloidNews. I then use a main handler which routes these out to their respective handlers. If i pass things by reference I will get type slicing and thus lose all ability to have an inheritance tree of events.

Share this post


Link to post
Share on other sites
Quote:
Original post by speciesUnknown
If i pass things by reference I will get type slicing

Err... you mean object slicing? It only occurs when passing things by value. Shared_ptr isn't enabling anything other than lifetime extension.

And on a barely sidetangent, FWIW, I'm looking forward to C#4's dynamic kewyord because it will end up helping simplify what you're doing:
class Message { ... }
interface IMessageHandler {
bool Handle( Message message );
}


class BadNews : Message {}
class GoodNews : Message {}
class TerribleNews : BadNews {}

class SomeMessageHandler : IMessageHandler {
void DoHandle( GoodNews ) { ... }
void DoHandle( BadNews ) { ... }
void DoHandle( Message ) { ... }

public void Handle( Message message ) { DoHandle((dynamic)message); }
}

Share this post


Link to post
Share on other sites
It looks to me like the fundamental problem is that you want the message handling to depend on both the message type and the handler type. This is called "double dispatch", and [google] knows many things thereabout.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this