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