19-Soft-B17 Data Visualization · December 2014
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.
In conventional object-oriented programming, objects interact by calling one another's methods directly and synchronously: when object A calls a method on object B, A's execution pauses and control transfers into B's code, which typically runs in the same thread and address space and may read or modify B's (and, through references, other objects') state immediately. When multiple threads call methods on shared objects concurrently, this direct, synchronous, shared-state model requires explicit synchronization (locks, monitors) to avoid race conditions, and getting that synchronization right is notoriously error-prone. Actor-oriented programming restructures concurrency around independent actors, each of which encapsulates its own private state that no other actor can access directly. Actors interact exclusively by sending asynchronous messages to one another's mailboxes; a sending actor does not block waiting for the message to be processed, and a receiving actor processes the messages in its mailbox one at a time, so an individual actor's own state is never touched by two operations simultaneously. In response to a message, an actor may update its own private state, send messages to other actors, or create new actors — but it can never directly read or write another actor's state.
Because there is no shared mutable state between actors, and each actor processes its own mailbox strictly sequentially, actor-based programs achieve concurrency safety without explicit locks: the "one message at a time per actor" rule plays the same role a lock would in an OO program, but it is enforced structurally by the model rather than by disciplined, error-prone application of synchronization primitives by the programmer. This makes actor-oriented programming preferable in highly concurrent, distributed systems — the canonical example is a real-time chat or messaging server handling many thousands of simultaneous client sessions. Modelling each user session (or each chat room) as its own actor means every session's state (connection info, message history, membership list) is naturally isolated: a session actor only ever changes its own state in response to messages ("user sent this," "user joined that room"), so there is no shared data structure that every connection thread would otherwise need to lock in order to update safely. Actors additionally map cleanly onto distribution: because all interaction between actors is already message passing rather than direct memory access, an actor-based system (e.g., built on Erlang/OTP or Akka) can transparently place different actors on different machines — a message sent to a remote actor looks identical in code to one sent to a local actor — whereas an OO system built around direct method calls and shared references generally cannot be distributed across machines without substantial re-architecture, since a "method call" that crosses a machine boundary is no longer a simple, cheap, synchronous operation. An OO design remains preferable for the common single-threaded or lightly-concurrent case, where the actor model's message-passing overhead and asynchronous style would add complexity without a corresponding benefit.