Axum has a couple of storage modifiers not found in most other languages (although several languages incorporate futures and / or promises, similar concepts).

Axum has three modifiers that are useful mostly with concurrent algorithms, for synchronization between agents within a domain or between interleave branches within an agent. For inter-domain synchronization, channels remain the only method.

Here’s an example:

async int x; 
const string str; 
sync object obj;

These storage modifiers can be used for locals, parameters, domain and agent fields, etc. (but not as schema properties).

Such variable all have in common that they can be empty or full at any given point in time. Being empty is different from a nullable type having the value null, it literally means that the variable does not hold a value of any kind and therefore cannot be read. Readers will block when trying to get the value out of an empty location (of course, the compiler does the right thing to make it scalable).

As a category, we call this “empty full storage.” Readers of an empty storage location always block and writers can always write to an empty location. What is more interesting is what happens when the variable is full. We have the following possibilities:

Writers may…

  • … block until the location is empty.
  • … throw an exception.
  • … overwrite the value already stored at the location.

Readers may…

  • … get a copy of the data and leave the location full.
  • … empty the location after reading it.

One can imagine having support for these operations on a single storage component, but we have chosen to define different components for three out of the six combinations that are possible.

They are:

  • async, where writers overwrite and readers copy
  • sync, where writers block and readers empty
  • const, where writers throw and readers copy

Async is roughly the normal variable storage semantics, except that it can be empty if not initialized; sync is roughly a synchronous producer / consumer buffer, and const is a single-assignment variable. One neat thing is that ‘const’ is a generalization of a C# const variable; with the exception of the possibility to deadlock, it behaves just like a const in that each read operation that completes will return the same data.

If you return a const from a method, you are essentially giving the caller a handle to a future value. Const variables are not as flexible as full-fledged promises, though.

All three are useful for communicating between agents, while async and const are also useful when used in dataflow networks, as they are sources and targets. You can imagine a network which processes an incoming message and places the result in a const variable, which is then read by some control-flow-based code that blocks until the value is available.

When used in networks, both async and const act as broadcasters; the only difference is that const variables will only broadcast one single message to its targets.

Three Questions

Empty / full storage is one of the more controversial aspects of Axum among the members of the internal team. There are those who think syntactic support in the language is useful and necessary, and there are those who would prefer to just see runtime classes implement these concepts. Which is right? I suspect it’s hard to answer that until you try it out for real, but it’s worth thinking about a bit.

Also, are the three above the right set? Artur Laksberg posted something on throttling earlier; his first example, where messages are dropped by the consumer could be reduced to a one-line modification of the consumer agent code if we had something where writers overwrite and readers empty. Are there other things we’re missing? throw/empty seems like a recipe for introducing races in code, and block/copy seems, well, silly…

Third, there are those on the team who would argue that ‘async’ is a bad moniker for its particular semantics (overwrite/copy). I would disagree, but there is another language feature that we all agree it would be better for, so we want to find another keyword for the storage modifier, and I’m therefore asking for your help with that. It has to be short (4-5 characters) and a good mnemonic for the semantics of the storage. Any and all suggestions will be considered…

Niklas Gustafsson