I have several questions around the actor model, data structures and the functional programming aspects of the IC

Actor model vs Immutable variables

As far as I understand immutable variables allow programs to be executed concurrently as different functions cannot refer to the same state and thus prevent unintended mutations. There can still be the case where one process refers to an old state, however, this seems to be an easier problem to solve (if fully functional, the process can simply run again when realizing that there is a new state, correct?). So the IC is using immutable data structures as well as the actor model for communication between canisters. I don’t understand which problem the actor model is exactly solving and which problem immutable data structures are solving, and why both are needed?
In this talk: Community Conversations | Overview of Motoko, the Native Language of the IC - YouTube, Andreas Rossberg mentioned that the actor model is helping to prevent deadlocks and race conditions but isn‘t that already what the immutable data structures are preventing? It all makes intuitive sense but I’d like to really get it.

The actor model is a way to scale concurrent programming beyond the confines of single machine to a distributed setting where shared memory is too expensive to implement. Since actors (like separate machines) can only communicate by message passing, there is no need to implement the abstraction of shared memory which can be very difficult to provide across multiple machines. If messages could transmit mutable data, then a sender would expect to be able to observe changes to data made by receivers, and vice versa, re-introducing the need for shared memory. By restricting message payloads to immutable data, the data can be sent by just copying it, without having to preserve the identity of its mutable parts (because their aren’t any).

Maybe this helps: Actors and async data :: Internet Computer

Messages

What are the messages between actors exactly? Where are they stored and what is the structure of them?

At the level of the IC, messages are just binary data (byte sequences) that are stored on the chain up until the beginning of the last epoch - the IC, unlike other block chains, doesn’t not store all of its history since genesis. Roughly speaking a message will contain the address/principal of the receiver, the desired target method name and the binary payload of the method together with some record of the call context awaiting a response to that message.

Motoko and other languages that communicate via Candid (e.g. Rust canisters when compiled with the cdk), interpret that binary data as typed, immutable Candid values. Candid provides a high-level serialization/deserialization format for typed data that is transmitted, by the IC, as raw, untyped binary data, between canisters.

Asynchronicity vs Synchronicity

Generally, I also don‘t fully understand the debate around the synchronous vs asynchronous design of blockchains. Not sure what to ask here, I’m simply looking for a rough explanation on this, especially in relation to having subnets and the actor model on the canister level.

I’m not sure about blockchains, but for general concurrency and distributed programming I can say this:

Roughly speaking, asynchronous messaging scales better to a distributed setting because the sender of a message need not block waiting for the response to a message before doing other things. This helps to hide the latency of communication (which is high for the IC and blockchains in general) by allowing the sender to initiate and await the responses to several messages in parallel.

Functional programming

I would like to understand better when/if people would use immutable data structures “within” canisters/actors?

Both immutable and immutable data structures have their uses within canisters. Immutable ones tend to be easier to reason about can be an advantage when correctness is a priority or when the ability to revert to a previous version of a data-structure is useful. Mutable data structures can be more time and space efficient. Like other imperative functional languages such as ML and Scheme, Motoko supports both.

Stable Data Structures

Why can only immutable data structures be stable? Andreas Rossberg was mentioning that the structure of memory can change for mutable structures, what was meant by that? This one is certainly a lack of basic understanding on my side on how memory works…

Actually, that’s not the case for Motoko - perhaps Andreas was referring to something else.

In Motoko, stable types extend (immutable) shared types to additionally allow mutable arrays and mutable record fields. Like shared types these can’t contain (local) function values or objects, for the simple reason that the code referenced by a function value or object method will not be available or even be meaningful after the actor has been upgraded.

However, it’s true that shared data (stuff that can be sent in message), cannot be mutable, so that the (encoding of) that data can simply and easily be copied between actors without having to preserve the identity of any mutable parts (since there aren’t any) (see above).

5 Likes