www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dispatching values to handlers, as in std.concurrency

reply =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
I have a list of functions which receive values of different 
types, like in std.concurrency...

     // example from std.concurrency
     receive(
          (int i) { writeln("Received the number ", i);}
      );

...although in my case I can probably live by with only accepting 
objects.

I built a list of the handlers and the message classes they 
accept. My problem is that I don't know how to check if the 
message I have to dispatch is of the class the handler accepts 
*or a subclass*. I only managed to check for class equality:

     if(typeid(msg) == typeHandler.type)
     {
         typeHandler.handler(msg);
     }

How can I also accept subclasses?

Thanks,
Luís
May 06 2013
next sibling parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Monday, 6 May 2013 at 17:03:20 UTC, Luís Marques wrote:
 I have a list of functions which receive values of different 
 types, like in std.concurrency...

     // example from std.concurrency
     receive(
          (int i) { writeln("Received the number ", i);}
      );

 ...although in my case I can probably live by with only 
 accepting objects.

 I built a list of the handlers and the message classes they 
 accept. My problem is that I don't know how to check if the 
 message I have to dispatch is of the class the handler accepts 
 *or a subclass*. I only managed to check for class equality:

     if(typeid(msg) == typeHandler.type)
     {
         typeHandler.handler(msg);
     }

 How can I also accept subclasses?

 Thanks,
 Luís
Just cast it - http://dlang.org/expression.html#CastExpression Casting object `foo` to type `Bar` will yield `null` if `foo` is not an instance of a `Bar` or of a subclass of `Bar`. This is particularly usefull combined with a declaration inside an `if` statement: if(auto castedObject = cast(typeHandler.type)msg) { typeHandler.handler(msg); } BTW, for this to work `typeHandler.type` needs to be known at compile-time.
May 06 2013
parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Monday, 6 May 2013 at 21:20:49 UTC, Idan Arye wrote:
 BTW, for this to work `typeHandler.type` needs to be known at 
 compile-time.
That's the rub. This list of handler is dynamic, so `typeHandler.type` is a TypeInfo, not a compile-time type.
May 06 2013
parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Monday, 6 May 2013 at 21:26:03 UTC, Luís Marques wrote:
 On Monday, 6 May 2013 at 21:20:49 UTC, Idan Arye wrote:
 BTW, for this to work `typeHandler.type` needs to be known at 
 compile-time.
That's the rub. This list of handler is dynamic, so `typeHandler.type` is a TypeInfo, not a compile-time type.
If the type handlers are your own classes, then you can let them check it. Have a method in the handlers that check if an object can be handled by that handler, and use it on each handler until you find one that fits.
May 06 2013
parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Monday, 6 May 2013 at 23:53:51 UTC, Idan Arye wrote:
 If the type handlers are your own classes, then you can let 
 them check it. Have a method in the handlers that check if an 
 object can be handled by that handler, and use it on each 
 handler until you find one that fits.
I don't understand. Imagine I have: class X { void handleFoo(Foo msg) { ... } void handleBar(Bar msg) { ... } } I want to register an instance of X to receive messages of type Foo (or subclass) and messages of type Bar (or subclass) in the respective handler methods. Where are you proposing for your check to be implemented?
May 06 2013
parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Tuesday, 7 May 2013 at 00:15:06 UTC, Luís Marques wrote:
 On Monday, 6 May 2013 at 23:53:51 UTC, Idan Arye wrote:
 If the type handlers are your own classes, then you can let 
 them check it. Have a method in the handlers that check if an 
 object can be handled by that handler, and use it on each 
 handler until you find one that fits.
I don't understand. Imagine I have: class X { void handleFoo(Foo msg) { ... } void handleBar(Bar msg) { ... } } I want to register an instance of X to receive messages of type Foo (or subclass) and messages of type Bar (or subclass) in the respective handler methods. Where are you proposing for your check to be implemented?
I assume that `typeHandler` in your original code is *not* of type `X` - since it has a single `handler` method while `X` has two, with different names. That means that at some point, you had to create it - let's assume it's type is called `TypeHandler`. There is either a global function, static method, or constructor where you create a `TypeHandler` and pass to it the delegate you want to register. Now, if that function/method/constructor is templated - than you already have at compile time the type you want to handle, so you can prepare the check there(anon function?) If it's not templated - make it templated! You don't have to make the entire `TypeHanler` templated, just the method that creates it. There, you can create an anonymous function that receives `Object` and returns `bool` and all it does is check for type, and you can have a field in `TypeHandler` that keeps that function and uses it to check if it can handle a certain type.
May 06 2013
parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Tuesday, 7 May 2013 at 06:19:24 UTC, Idan Arye wrote:
 If it's not templated - make it templated! You don't have to 
 make the entire `TypeHanler` templated, just the method that 
 creates it. There, you can create an anonymous function that 
 receives `Object` and returns `bool` and all it does is check 
 for type, and you can have a field in `TypeHandler` that keeps 
 that function and uses it to check if it can handle a certain 
 type.
Thanks. It took me a while to understand what you meant, but it's working.
May 24 2013
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
On May 6, 2013, at 10:03 AM, "Lu=EDs.Marques" =
<luismarques gmail.com>" puremagic.com <luismarques gmail.com> wrote:
=20
 How can I also accept subclasses?
How are the messages stored? std.concurrency uses Variant.convertsTo.=
May 06 2013
parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Monday, 6 May 2013 at 23:48:11 UTC, Sean Kelly wrote:
 How are the messages stored?  std.concurrency uses 
 Variant.convertsTo.
I had looked at Variant.convertsTo but (IIRC) it accepts a type (not a TypeInfo) and in my design I no longer had the type avaliable in the place where I would use the convertsTo, only the TypeInfo. I dispatch my messages as they come, so I don't store them. I only store the handler info, in the format Tuple!(TypeInfo, handler).
May 06 2013