Thoughts on Spek: The usage of channels and ports

I haven’t touched the Spek project in a few weeks and decided to give it some attention tonight. In playing with Java, Ruby, Python, and Node.js over the past couple of months, I’ve wondered what sort of additional syntax or overall languages changes I should consider before finishing the grammar.

The Spek language is pretty much a duplicate of the Axum language developed by Microsoft back in 2009. I’ve only made a really small change to the syntax for how a developer would interact with a channel and possible network operators, but the rest of the language is exactly the same so far.

For instance, this is the Axum way of retrieving and sending to the channel:

public domain MainDomain
{
    public agent MyMainAgent : channel Application
    {
        public MyMainAgent()
        {
            var cmdArgs = receive(primary::Start);
            Console.WriteLine(“Hello World!”);
            primary::Done <-- 0;
        }
    }
}

In this particular usage, the ‘MyMainAgent’ is utilizing a method off the channel like you could do with methods on a base class in C#. I’m not a big fan of the double-colon from my PHP days, and have been thinking about a lambda expression with a send and receive operator that feels natural to people in the C# world.

Channel functions, ports, and patterns are another area in particular of Axum that I don’t quite care for and would like to change before getting into implementation details for the Spek language. While I understand the reasons behind channel patterns in the Axum language, it seems that their implementation could be a concern for deadlocks, which even the Axum language designers theorized in their own literature for the language. For channel ports, I find them highly valuable, but not with multiple input ports and single output. And I’m on the fence about channel functions.

If you aren’t familiar with channel functions, they are essentially predicates for pattern matching. In the world of Axum, as you set values on a channel through what are called ‘input ports’, you can advance it’s state and fire certain functions or predicate checks that evaluate the values being passed unto it.

According to the Axum Language Specification, it says this about the reasoning behind channel ports and patterns:

If a channel declaration is seen as providing a vocabulary for a conversation between two parties, it may also be necessary to define in what order certain things may be said, as well as defining how the conversation is ended. This defines a grammar to go with the vocabulary, forming a little mini-language for a channel.

Without such a definition, a conversation is ended by convention and the convention may be encoded in conflicting ways on either side of the channel: A thinks that the exchange is done, while B waits for another value.

This rigidness in the language was meant as a way to provide strict communication contracts and seems to be a result of the work the team put into place for working with WCF. This is both for compatibility reasons, and because it seems to comprise the underlying components for the Axum networking pieces. While I see value in using WCF for implementations of SOAP endpoints, most people have moved onto using REST almost exclusively for new projects. As such, I don’t want the language to fail as a result of an underlying networking concept that had it’s place in time. The ability to use networking concepts should be implementation specific in my opinion.

Maybe I need to work with ADA or SR before I truly get what advantages the team was hoping to achieve with these concepts, given that those languages were inspirations for Axum. But I don’t currently see a need for these barriers within the language.

Given that the message-passing based languages always use the mailbox example, I think the removal of the channel patterns would make more sense. All the mailbox should care about is that the messages given to it are addressed to it and that it has postage. It shouldn’t care if you dated, opened, closed, or signed your letter properly.

And a working thought about channel functions is that it could essentially play postmaster by verifying the contract elements, such as ensuring that the channel meets the proper input requirements just as before, but in a non-blocking way. I’ll have to work through the idea more and show you.

Fast forward a few years into the future…

The developers behind the Axum language still saw value in providing an Actor based language to the .NET framework, but for whatever the internal reasons were, the project was shuttered and the team went on to start another initiative called Project Orleans. The original work for Axum went on to become the MailboxProcessor in F# (based in part on this blog entry) and the TPL framework in .NET 4.

In the Project Orleans framework that you can now download and use, it doesn’t seem to have any concept of channel patterns, relying just on plain-old-goodness of value and reference type passing. While that is probably because it’s just a framework utilized by a shared-memory language like C# or VB.NET and the concept couldn’t be enforced at design time, it’s still good that their work shows that it’s not necessarily required. Rather than letting the channel dictate what is required, letting the agents make that determination and then raise errors as necessary if the desired state isn’t met. While I like the concept of always being in a known good state, at least you aren’t deadlocking the application and allows a loosely coupled architecture.