Immutable view of class instance


I occasionally encounter the situation where a class instance holds some mutable state, which one specific part of the program is responsible for updating, and many parts of the program need read-only access to.

I am not worried about synchronizing accesses—the program may well be single-threaded. The important thing is that I need references to a class instance, where the holders of those references are not able to modify that instance.

Now, I could make an indirection layer—say, a struct holding a reference to the class instance, and exposing only the non-mutating parts of the API. But even that requires knowing which methods are non-mutating, and currently one is not allowed to mark members of a class as mutating.

Is there a recommended approach to this, and/or a plan to allow marking class members to indicate whether they mutate the instance?

(Jordan Rose) #2

Mutating and reference semantics gets very tricky very quickly (cf. C++). Do the holders of the non-mutating instance reference have a guarantee that the instance's properties won't change while they're using it, or are they just not allowed to modify them through that reference?

The Foundation approach of NSFoo / NSMutableFoo may be an appropriate one here.

(Michel Fortin) #3

I played with the idea of compiler-enforced value semantics earlier and wrote this exploratory proposal. I do believe the idea would work, but don't think it's very realistic to add this to the language.

To me, it sounds like the idea discussed at the end of this recent thread would work better. Inspired from NSCopying, add a Cloning protocol with a clone() method you can call every time you need a copy detached from any previous reference. Maybe allow the compiler to auto-generate the implementation of the clone() method if all the members conform to Cloning. And maybe add an @autocloning type modifier you could use to tell the compiler to call clone() every time a copy is made.

With all these features, you could have a signature like this:

struct Dictionary<@autocloning Key, Value> 
    where Key: Clonable, Hashable
{ ... }

and be sure keys won't mutate under your nose because clone() will be called automatically at every copy. (Assuming clone() is implemented properly.) Of course adding this to Dictionary would break source-compatibility.