Benedict Cohen
Benedict Cohen

Reputation: 11920

What should the return type be when a method can return subclasses?

Here are a few methods from some Apple classes:

- (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

It is reasonable to expect all of these methods to return subclasses of the return type. Due to this the returned object is often assigned to a variable of the expected type, eg:

BCCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

This makes the compiler unhappy; a cast solves this, but casting like this is dirty:

BCCustomTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

However, when the return type is id, this cast can be removed, albeit at the cost of some type safety, resulting in my code being cleaner:

BCPerson *person = [NSEntityDescription insertNewObjectForEntityForName:BCPersonEntityName inManagedObjectContext:context];

Personally, I prefer it when the return type is id. Is there any rationale that Apple used for choosing one approach over the other, or is it simply due to the preference of the developer who wrote the methods?

Upvotes: 4

Views: 559

Answers (4)

Nick Moore
Nick Moore

Reputation: 15857

Casting is dirty, but having the method return id is dirtier, since there may be hidden danger lurking beneath, which the compiler has no chance to warn you about. Doing the cast is just saying to the compiler 'you've warned me, now let me face the peril'.

Upvotes: 1

paulbailey
paulbailey

Reputation: 5346

If the return type is id then surely the method definition is less helpful? You could receive any type of object, and there could be no compile-time type checking.

In the end, setting an subclass object just causes a compiler warning, which is a preferable situation to a potential bug caused by a typo, or misreading the documentation for that matter.

Upvotes: 1

Pascal
Pascal

Reputation: 16941

I really prefer the casting. If you return id from these methods, the compiler will not warn you at all since it can't know what will be returned there. If you cast the return value correctly (and not cast to id), then you can be sure that you've done it right if you don't get a warning. All it takes is to write one class name more.

BCCustomTableViewCell *cell = (BCCustomTableViewCell *)[tableView dequeue...];

The rationale of not returning id is that you don't return just anything, but a given class and its subclasses. From this example method, you always get a table view cell, you can rely on it responding to certain methods (unless you mess up your subclass badly, that is). If you return id you can't rely on anything, plus the compiler won't warn you.

Edit: I'm only referring to the instance methods, not the class methods. Williham explains that difference.

Upvotes: 2

Williham Totland
Williham Totland

Reputation: 29019

In the three examples you describe, two different principles are at work:

In the two first, Apple wants you to use a cast as a "I know what I'm doing" sort of thing: When you are accessing a generic object through an identifier, you might end up being surprised by the class of the return value, unless you know what you're doing.

In the latter example, the method is essentially a factory method, equivalent to alloc init, and in most cases you had better know what it is you are making.

In other words, to answer your question:

For a factory method, id, for a getter, the same as the setter.

Upvotes: 4

Related Questions