Search code examples
c++objective-cdesign-patternsmutability

Mutability design patterns in Objective C and C++


Having recently done some development for iPhone, I've come to notice an interesting design pattern used a lot in the iPhone SDK, regarding object mutability.

It seems the typical approach there is to define an immutable class NSFoo, and then derive from it a mutable descendant NSMutableFoo. Generally, the NSFoo class defines data members, getters and read-only operations, and the derived NSMutableFoo adds on setters and mutating operations.

Being more familiar with C++, I couldn't help but notice that this seems to be a complete opposite to what I'd do when writing the same code in C++. While you certainly could take that approach, it seems to me that a more concise approach is to create a single Foo class, mark getters and read-only operations as const functions, and also implement the mutable operations and setters in the same class. You would then end up with a mutable class, but the types Foo const*, Foo const& etc all are effectively the immutable equivalent.

I guess my question is, does my take on the situation make sense? I understand why Objective-C does things differently, but are there any advantages to the two-class approach in C++ that I've missed? Or am I missing the point entirely?

Not an overly serious question - more for my own curiosity than anything else.


Solution

  • Objective-C is too dynamic. In C++ const-qualification is enforced at compile-time, and any violations of const-qualification at runtime (such as modifying a const-qualified object through a non-const-qualified pointer) is undefined behaviour.

    It is partly the same as the reason why there are no private methods in Objective-C. You are free to send whatever message you want to any object. The runtime dispatch takes an object and a message, and resolves a method implementation to invoke.

    if const qualified objects could only invoke const qualified methods, it would completely ruin the dynamic nature of Objective-C and Foundation because such a check would need to be done at runtime (first check would determine whether the message being sent resolves to a const-qualified implementation for that specific instance, and another check to determine whether the instance itself was const-qualified). Consider this theoretical example:

    NSArray *mutableArray = [[NSArray alloc] init];
    
    NSString *mutableString = @"I am a mutable string";
    const NSString *immutableString = @"I am immutable because I am const-qual'd";
    
    [mutableArray addObject:mutableString];
    [mutableArray addObject:immutableString]; // what happens?!
    
    // and what happens here (both immutable and mutable strings would respond
    // to the same selectors because they are the same class):
    [mutableArray makeObjectsPerformSelector:@selector(aMutableOperation)];
    

    Suddenly you lose dynamics. As it is now, mutable and immutable objects can sit together in an immutable or mutable collection.

    Having a mutable subclass keeps the dynamic nature of Objective-C and keeps the runtime simple. There was a similar topic a while ago about private methods.