So, I've just started looking at a new .NET language from Microsoft called Axum (available here). At this point, you might be tempted, as I originally was, to complain that there’s no need for Microsoft to produce yet another language. After all, we have perfectly serviceable languages in C#, VB.NET and (for the linguistically adventurous) F#. Why on earth is Microsoft wasting its time on another language?
Well, it turns out that there’s a very good reason for them to be looking into creating a new one. Axum fits a niche that, while other languages could do what it does, these other languages weren’t originally designed for. Axum is designed for applications that require parallel task execution. As it is designed to create parallel applications, the language offers first class constructs for achieving parallelisation.
The Axum documentation, sparse as it is at the moment, identifies that some tasks are easily amenable to parallelisation because the tasks are independent of each other, and require little synchronisation; other applications have dependencies that require coordination. Axum, as a language, allows us to arrange the coordination between these components in a way that closely matches the way we would conceive of the solutions.
I said, before, that other languages offer us the ability to parallize tasks, so it’s hard to see what Axum brings to the ball, so to speak. Well Axum removes one feature that normally causes problems for developers creating parallel applications if they aren’t careful. It removes the ability for components to share or mutate state from other threads. It provides an isolation model that promotes a disciplined access to shared state, and encourages its use from the start rather than being added as an afterthought.
At this stage, I must stress that Axum is an experimental language, similar enough to C# not to be daunting. This similarity, though, could also cause problems at first glance because it’s so easy to try and do things the C# way, which is not always the Axum way.
Without further ado, we’re going to write our first Axum application. It’s a variation of the Hello World described in the Axum Programmers Guide. Assuming you’ve downloaded and installed Axum in either Visual Studio 2008 or Visual Studio 2010, select File > New > Project > Axum > Windows > Console Application. Call the application HelloAxum
and click OK. You’ll now get some boilerplate code which you’re going to replace with:
using System;
agent HelloAxum : Microsoft.Axum.ConsoleApplication
{
override int Run(string[] args)
{
Console.WriteLine("Hello Axum");
}
}
The first thing to note about this application is that it has full access to .NET features, such as the BCL or Console.WriteLine
.
Second, we’ve defined our unit of work as an agent rather than a class. An agent is conceptually similar to an actor (in fact Axum is well suited to being mapped out with UML). Agents represent autonomous elements that communicate using messages and so on. Here’s my first problem with Axum; why not call it an actor? Why define a new term here? It just feels a natural fit, for me, to use actor here rather than agent.
Anyway, terminology quibbles aside, agents are very different to developing using OOP. These differences are by design and are there for very good reasons. Agents don’t provide public
methods or exhibit state, so you can’t modify fields externally. This means that you can’t call an agent method directly, so you might be tempted to think that methods are useless here. What you can do and what you do, in fact, do, is send a message to the agent and arrange for the agent to get back to you with a response when it is appropriate.
In our sample application, we derive from a ConsoleApplication
agent which provides the basis for working with console applications.
At this stage, you may be feeling distinctly underwhelmed. After all, we’ve not really done any parallel processing. It’s time to mix things up a bit and do some parallel work. Let’s actually create a couple of agents and pass messages between them. Along the way, we’re going to learn some of the terminology in Axum starting with channels and ports.
Remember that we said that we couldn’t reach into agents? Well, how do we set or get this data? The ability to do this lies in channels – which (in OO terms) defines the interface
that our decoupled agents will communicate through. The ports, on a channel, define the inputs and outputs.
In order to define a channel, we use the channel
keyword. Here’s a simple channel
:
channel HelloAxumChannel
{
input string Name;
output string Text;
}
When you use a channel
,
data goes in, cunningly enough, into the inputs and is returned via the outputs. Notice that the channel
doesn’t actually tell you how it does it – it only tells you what it does. Now let’s add the implementation.
agent HelloAgent : channel HelloAxumChannel
{
public HelloAgent()
{
string item = receive(PrimaryChannel::Name);
PrimaryChannel::Text <-- string.Format("Hello {0}", item);
}
}
This agent waits for a message to arrive on the Name port (the receive
statement). Once this is received, it sends a message to the Text port on the PrimaryChannel
(the PrimaryChannel
is a public
property on the channel
that gives access to the channel being implemented). It then sends a message to the Created port. Now, received is a blocking operation, meaning that it waits until a message arrives on that port. Now, let’s do something with this – let’s actually “instantiate” this agent and pass a message to it.
public domain Program
{
agent HelloAxum : Microsoft.Axum.ConsoleApplication
{
override int Run(string[] args)
{
var proc = HelloAgent.CreateInNewDomain();
Console.Write("Enter your name:");
string value = Console.ReadLine();
proc::Name <-- value;
string outputText = receive(proc::Text);
Console.WriteLine(outputText);
Console.ReadKey();
}
}
}
In order to instantiate our agent, we use CreateInNewDomain
. Once it’s been created, we pass messages into it using <–. Again, this process waits for a message from our agent in proc::Text
. That’s it – we’ve got a parallel application. (Here it is in all its glory):
using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
namespace AxumApplication1
{
public domain Program
{
agent HelloAxum : Microsoft.Axum.ConsoleApplication
{
override int Run(string[] args)
{
var proc = HelloAgent.CreateInNewDomain();
Console.Write("Enter your name:");
string value = Console.ReadLine();
proc::Name <-- value;
string outputText = receive(proc::Text);
Console.WriteLine(outputText);
Console.ReadKey();
}
}
}
channel HelloAxumChannel
{
input string Name;
output string Text;
}
agent HelloAgent : channel HelloAxumChannel
{
public HelloAgent()
{
string item = receive(PrimaryChannel::Name);
PrimaryChannel::Text <-- string.Format("Hello {0}", item);
}
}
}
So, do I like Axum? Well, yes I do – I’ve only just begun to scratch the surface of what it can do here; look for more from me in future blogs. I only hope that it actually goes somewhere – I’d hate to see the project die for lack of interest. Obviously, you know my love of WPF, so I’d also like Axum to provide first class WPF integration. I’m watching Axum with interest.