Dispatching on a variant

Jeremie Pelletier jeremiep at gmail.com
Sat Sep 26 13:18:38 PDT 2009


language_fan wrote:
> Sat, 26 Sep 2009 12:25:23 -0400, Jeremie Pelletier thusly wrote:
> 
>> Justin Johansson wrote:
>>> language_fan Wrote:
>>>
>>>> Sat, 26 Sep 2009 09:32:55 -0400, Justin Johansson thusly wrote:
>>>>
>>>>> I've had a good poke around the forums and couldn't find anything on
>>>>> this so ...
>>>>>
>>>>> What's the recommended method for dispatching code off the runtime
>>>>> type of a variant variable (Phobos D2 std.variant)?
>>>>>
>>>>> Does one use a bunch of
>>>>>
>>>>> if ( var.peek!(type1)) { ... }
>>>>> else if ( var.peek!(type2)  { ... }
>>>>>
>>>>> for all N possible types, or is there a better & faster way with a
>>>>> switch or jump table of sorts?
>>>> If the type count gets large, how fast it is depends on the backend
>>>> optimizations of the compiler. In the worst case it is a O(n) time
>>>> linear search. A jump table or almost any other way of dispatching
>>>> would be faster. If the variant had an integral tag field, it could be
>>>> used in a switch; that way the compiler could easily optimize it
>>>> further with the currently available constructs.
>>>>
>>>> This problem is solved in higher level languages by providing pattern
>>>> matching constructs. The compiler is free to optimize the code the way
>>>> it likes:
>>>>
>>>>   case var of
>>>>     type1 => ...
>>>>     type2 => ...
>>>>     ...
>>>>
>>>> But since no C-like language has ever implemented pattern matching, it
>>>> might be too radical to add it to D.
>>> Thanks both for replies.
>>>
>>> I've got about 2 dozen types in the variant so the O(n) really hurts.
>>> The variant thing seemed like a really cool idea at the time but now
>>> ... Without something like suggested above or a computed goto on typeid
>>> or Andrei's visitator, it almost pushes me to backout from using
>>> variants and having to redesign around some common base class or
>>> interface and using virtual function dispatch. :-(
>>>
>>>
>> I see this sort of design in C all the time with event handling,
>> although its with unions rather than discriminated unions, the same
>> logic applies.
>>
>> enum EventType {
>> 	Mouse,
>> 	Key,
>> 	Move,
>> 	...
>> }
>> struct Event {
>> 	EventType type;
>> 	union {
>> 		MouseEvent mouse;
>> 		KeyEvent key;
>> 		MoveEvent move;
>> 		...
>> 	}
>> }
>>
>> void dispatchEvent(const(Event)* event) {
>> 	...
>> 	with(EventType) final switch(event.type) { case Mouse: ...
>> 	case Key: ...
>> 	case Move: ...
>> 	...
>> 	}
>> 	...
>> }
>>
>> That's the logic with standard unions, you should be able to get
>> something similar with variants. It's more code to setup, but you end up
>> with a simple jump table from the switch, and final in D makes it easy
>> to change EventType without forgetting to update dispatchEvent.
> 
> Exactly, this is what I mentioned previously. Isn't it ugly compared to
> 
>   type Event = Mouse | Key | Move;

This can be confusing, for example the first thing that comes to mind 
for me is that Event is the bitwise OR result of 3 constants, not an 
enumerated type.

Besides, how is it any different than:

enum { Mouse, Key, Move };

>   void dispatchEvent(Event event) {
>     match(event) {
>       Mouse m => m.squeek();
>       Key k => ...
>       ...
>     }
>   }

match(event) is no different than switch(event), except that pattern 
matching often implies runtime semantics and is often slower than a 
straight jump table generated from a switch.

> What's with all the language proposals here? Why hasn't anyone proposed 
> this before? This is in fact very helpful - that's why several modern 
> languages have adopted it.



More information about the Digitalmars-d mailing list