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.
An immutable object is an object whose observable state cannot be changed after it has been constructed — every field is set once, at construction time, and no method exists (or is permitted) to modify it afterward; any operation that appears to "change" the object instead constructs and returns a new object representing the modified value, leaving the original untouched. Common examples include Java's String (concatenating two strings produces a brand-new String object rather than mutating either operand) and boxed numeric wrapper types such as Integer, as well as, by convention, many value-object types a programmer designs deliberately (an immutable Point, Money, or DateRange class that offers only a constructor and read-only accessors). A mutable object, by contrast, exposes methods that change its internal state in place after construction, so the same object reference can observe different state at different points in time.
This distinction has a direct and significant effect on thread safety. A data race requires two conditions to both hold: shared state, and at least one thread mutating it while another accesses it concurrently without synchronization. An immutable object structurally removes the second condition — because its state can never change after construction, there is nothing for a second thread to observe "mid-update," and no possibility of one thread reading a value while another thread is in the middle of writing it. Consequently, once an immutable object has been safely constructed and published (made visible) to other threads, it can be freely shared, read, and passed around by any number of threads simultaneously and without any locking whatsoever — there is no critical section to protect, because there is no mutation to protect it from. This is why immutable value objects are a standard building block of concurrent and functional-style code: passing a Money or DateRange instance between threads carries none of the risk that passing a mutable, in-place-updatable equivalent would.
Mutable shared objects, by contrast, require the programmer to explicitly protect every access with a synchronization mechanism — locks, monitors, atomic operations, or language-level guarantees such as Java's volatile — anywhere the object might be read or written from more than one thread, and to get the placement, granularity, and ordering of that synchronization exactly right, or the program suffers from classic concurrency bugs: lost updates (two threads read the same value, each computes an increment, and one update overwrites the other), torn/partial reads (a thread observes an object halfway through another thread's multi-field update), and visibility problems (a thread's local cache of a variable never observes another thread's write at all, absent a proper memory-barrier/synchronization construct). Because these bugs are timing-dependent, they are notoriously difficult to reproduce and debug, which is exactly why the standard practical guidance for concurrent programming is to prefer immutable objects wherever the data's use case allows, and to minimize the amount of genuinely mutable, thread-shared state to the smallest, most carefully synchronized core the design actually requires.