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.
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.