Thread overview
Dispatching values to handlers, as in std.concurrency
May 06, 2013
Luís Marques
May 06, 2013
Idan Arye
May 06, 2013
Luís Marques
May 06, 2013
Idan Arye
May 07, 2013
Luís Marques
May 07, 2013
Idan Arye
May 24, 2013
Luís Marques
May 06, 2013
Sean Kelly
May 07, 2013
Luís Marques
May 06, 2013
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
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
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
On May 6, 2013, at 10:03 AM, "Luís.Marques" <luismarques@gmail.com>"@puremagic.com <luismarques@gmail.com> wrote:
> 
> How can I also accept subclasses?

How are the messages stored?  std.concurrency uses Variant.convertsTo.
May 06, 2013
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 07, 2013
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 07, 2013
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 07, 2013
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 24, 2013
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.