Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does [NSMutableString stringWithString:@""] work?

Just wondering:

In NSString there is a static method called +stringWithString:. This is not redeclared/overridden in NSMutableString so we cannot assume that this will return an NSMutableString. In fact even in the NSString class the return type is defined as id and the doc states:

Return Value
A string created by copying the characters from aString.

What part of objective C am I missing in my knowledge to understand why this works and returns an NSMutableString? Especially because the base class NSString is not aware that we want a mutable string in return.

One could say that internally [Class alloc] is called which will generate an object of type NSMutableString, but even this is pure guesswork as we do not have the source code and stringWithString: could do whatever it wants internally.

Are all those class methods reimplemented in the subclass? And if yes why isn't this documented?

like image 225
Joris Mans Avatar asked Dec 01 '11 15:12

Joris Mans


2 Answers

In NSString there is a static method called +stringWithString:.

more approriately, it's a class method.

This is not redeclared/overridden in NSMutableString

In cocoa, the subclass does not need to redeclare the method. In fact, it would just produce a lot of noise (IMO). It only needs to redefine the method to provide its custom implementation.

so we cannot assume that this will return an NSMutableString.

We must assume that it will return a mutable string. A subclass can redefine its initializers and convenience constructors as needed in order to meet the required contracts without publicly redeclaring the method -- it only needs to define the method when the base's implementation is insufficient.

What part of objective C am I missing in my knowledge to understand why this works and returns an NSMutableString? Especially because the base class NSString is not aware that we want a mutable string in return.

It 'knows' because you have written [NSMutableString stringWithString:@"bah"] rather than [NSString stringWithString:@"bah"]. Like instance methods, class methods have an implicit self which allows them to pass the type through class methods. Therefore, class methods may be redefined/overridden as needed. The class methods may also use self to determine or message their type (example shortly).

One could say that internally [Class alloc] is called which will generate an object of type NSMutableString, but even this is pure guesswork as we do not have the source code and stringWithString: could do whatever it wants internally.

It should not be guesswork. In this case, you should file a bug if you were returned an immutable string. Otherwise, it works as advertised, regardless of whether they used one or more definitions.

Are all those class methods reimplemented in the subclass?

In the case of convenience constructors, it's more common to go through one of the designated initializers:

such an implementation could take the form:

@implementation NSString
+ (id)stringWithString:(NSString *)arg
{
    // self is either +NSString or +NSMutableString
    return [[[self alloc] initWithString:arg] autorelease];
}

although exceptions can often be made, and is often the case with optimized immutable/mutable types:

@implementation NSString
+ (id)stringWithString:(NSString *)arg
{
  return [arg imp_isMutable] ? [[[self alloc] initWithString:arg] autorelease] : arg;
}
...
@implementation NSMutableString
+ (id)stringWithString:(NSString *)arg
{
  return [[[self alloc] initWithString:arg] autorelease];
}
...

And if yes why isn't this documented?

They should not be redeclared or redocumented when the only difference is the class type which you have requested, unless they have some deviation from the base class or special note -- even in that case, it would be better to create a method with another name.

like image 110
justin Avatar answered Sep 22 '22 21:09

justin


NSMutableString is a subclass of NSString thus any method called on NSMutableString can be expected to work appropriately, and return an NSMutableString when it makes sense. The only method that comes to mind that doesn't follow that though is copy which by convention returns an immutable instance.

This is why your initializer methods return id rather than a concrete instance, and why all class methods should use [self alloc] instead of [MYActualClass alloc].

like image 40
Joshua Weinberg Avatar answered Sep 23 '22 21:09

Joshua Weinberg