Concurrency

OverviewImmutabilityShared ObjectsAdditional Techniques

Overview

Fantom tackles concurrency using a very different path from Java and C#. Java and C# use a shared memory model - all threads have access to each other's memory space. Synchronization locks are required to ensure that threads share data in a consistent manner. This concurrency model is quite powerful, but operates at a low level of abstraction. As such, even skilled programmers have a hard time writing code which is free of both race conditions and deadlocks. This model also makes it very hard to create composable systems because all system components must orchestrate their use of locking consistently.

The Fantom model of concurrency is based upon the following principles:

  • No Shared Mutable State: threads never share mutable state under any circumstances;
  • Immutability: the notion of immutability is embedded into the language itself. Immutable data can be efficiently and safely shared between threads (for example via a static field);
  • Message Passing: the actor API is built around the idea of passing messages between asynchronous workers;

Immutability

An object is said to be immutable if we can guarantee that once constructed it never changes state. Fantom supports these types of immutable objects:

By definition a const class is immutable - the compiler verifies that all the instance fields are themselves immutable and only set in the object's constructor.

Func objects are determined as mutable or immutable by the compiler depending on if the function captures mutable state from its environment. See Functions for more details.

Memory backed Buf objects can made immutable by calling the toImmutable method. The original bytes are transfered to a new readonly Buf instance.

The toImmutable method supported by List and Map is a mechanism to return a readonly, deep copy of the collection which ensures all that all values and keys are themselves immutable. The compiler will allow assignment to const List/Map fields during construction, but it implicitly makes a call to toImmutable. For example to declare a const list of strings:

// what you write
class SouthPark
{
  const static Str[] names := ["Stan", "Cartman", "Kenny"]
}

// what the compiler generates
class SouthPark
{
  const static Str[] names := ["Stan", "Cartman", "Kenny"]?.toImmutable
}

You can check if an object is immutable via the Obj.isImmutable method.

Shared Objects

Actors allow objects to be shared between threads. Specific APIs which will pass an object to another thread include:

All of these APIs require that an object is immutable to be safely passed between threads.

Additional Techniques

Although most Fantom code uses actors as its primary means of concurrency there are several APIs which can be used for more advanced situations:

  • AtomicRef: for sharing mutable ref to an immutable object
  • ConcurrentMap: for sharing map of immutable objects with thread safe mutation (uses Java ConcurrentHashMap under the covers).
  • Lock: re-entrant mutex locking