[dmd-concurrency] Pattern matching on message receives, error handling

Mark Kegel mark.kegel at gmail.com
Wed Jan 13 07:44:50 PST 2010


The reason I'm scared is fairly simple, I've seen this exact design
(well maybe not exact, but the similarities are too great to ignore)
used before. I worked for a couple of years on a large Telco system.
Message handling was its bread and butter. We had lots of independent
process with probably thousands of different messages flying through
the system.

One thing that got beat into my head was that you really, really want
to be able to easily trace the sequence of messages in a system. What
pattern matching gives you is a more concise notation for telling
outside users what is handled and what is not. That is the protocols
that actors use to communicate are made explicit, not left implicit
and thus recalcuated everytime you want to know how it works. In
essence you can segment your code more cleanly along logical
communication lines rather than function signature, since one function
signature might be the entry point for fifteen different completely
orthogonal messages.

It really all comes down to how easily the syntax of the language
scales to large designs. Sure, taking anonymous functions and then
testing for all messages that matching that signature is exactly as
powerful as pattern matching, but I would contend that its a lot less
readable.

So lets assume that you let receive() take some kind of pattern
object, what might this look like? To write it out in the worst
possible way, here's one idea:

receive( pattern("foo", _1) + (string a, string b) { ...},
            pattern("bar", _1) + (string a, string b) { ...},
            pattern(_1, _2) + (string a, string b) { ...},
            ...
          );

I've used _* placeholders similar to the way boost lambda does.

While I've intentionally made this as ugly (and self documenting) as
possible, I really have no idea how'd you'd clean this syntax up,
since I'm just not that familiar with D's introspection capabilites.
Does any one more familiar with D have a better way to implement
pattern matching?

Mark


On Tue, Jan 12, 2010 at 11:38 PM, Sean Kelly <sean at invisibleduck.org> wrote:
> On Jan 12, 2010, at 7:54 PM, Andrei Alexandrescu wrote:
>
>> Mark Kegel wrote:
>>> Call me silly, but how many of you have seen 1000 line switch
>>> statements when polymorphism was called for? And what is
>>> polymorphism but dispatch / pattern matching over argument type?
>>> So when I see code like this:
>>>       auto msg = receiveOnly!(Tid, int)();
>>>       if (!msg[0]) return;
>>>       writeln("Secondary thread: ", msg[1]);
>>>       msg[0].send(thisTid);
>>> ...where you the first thing you tell new readers about how to
>>> test what message you just got is with an 'if' statement, I get
>>> scared. Please give users a more elegant mechanism, and if you
>>> need ideas about what it could look like I would suggest that
>>> Scala offers a passable (and maybe even compatible) syntax.
>>
>> You have a point, but quite a weak one. First, the example above is not illustrative on the pattern matching capabilities of D; we'll get to those with the full-fledged receive() function. For now I just considered fine to send a null Tid to signal loop termination. With receive() you can dispatch to various functions depending on the types of the arguments. With introspection it's very easy to dispatch messages to an object depending on their types.
>>
>> I don't agree with the comparison with switch() vs. virtuals at all. The problem with switch() is that it breaks modularity by requiring all cases to be present in the same place. On the contrary, pattern matching _also_ requires all cases to be present together (which makes me believe it's much less powerful than it's cracked to be). So if I pattern match with
>>
>> patternmatch (receive()) {
>>    case int x: ...
>>    case (string a, int b): ...
>> }
>>
>> versus
>>
>> receive(
>>    (int x) { ... },
>>    (string a, int b) { ... }
>> );
>>
>> we're only talking about a difference in syntax, not power. So essentially you shouldn't be scared just because there's no built-in syntax for something that can be expressed within the existing language with the same power.
>
> It's worth adding that Erlang does provide pattern matching capabilities that have to be a run time in D, but I'm not sure this same capability is available in Scala, for example.  In our case, this will probably be handled manually by the user, with possibly some fancier way to do it later (metaprogramming can do quite a lot in D).  For example:
>
>    receive(
>        (int x) { ... },
>        (string a, int b) { if (a == "blah") return false; ...; return true; }
>    );
>
> Here, the second function checks string a to see if it matches a pattern, and returns true/false to indicate that there was a match.
>
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency
>


More information about the dmd-concurrency mailing list