views:

320

answers:

1

In Ruby, there's Modules and you can extend a class by "mixing-in" the module.

Module myModule
  def printone
    print "one" 
  end
end

Class myClass
  extend myModule
end

theOne = myClass.new
theOne.printone 
>> one

In Objective-C, I find that I have a set of common methods that I want a number of Class to "inherit". What other ways can I achieve this without creating a common class and deriving all from that common class?

+7  A: 

Categories are not really the right choice here, if I understand the question properly. The right feature is a protocol.

Let me give an example. Suppose you want a bunch of your classes to have a specific ability called "sing". Then you define a protocol:

@protocol Singer
    - (void) sing;
@end

Now you can declare that any of your own classes adopts the protocol the following way:

@interface Rectangle : Shape <Singer> {
    <snip>
@end

@interface Car : Vehicle <Singer> {
    <snip>
@end

Be declaring that they adopt the protocol they commit themselves to implement the sing method. For example:

@implementation Rectangle

- (void) sing {
    [self flashInBrightColors];
}

@end

@implementation Car

- (void) sing {
    [self honk];
}

@end

Then you use those classes for example like this:

void choral(NSArray *choir) // the choir holds any kind of singer
{
    id<Singer> aSinger;
    for (aSinger in choir) {
        [aSinger sing];
    }
}

Notice that the singers in the array don't need to have a common superclass. Notice also that a class can have only one superclass, but many adopted protocols. Notice finally that type checking is done by the compiler.

In effect, the protocol mechanism is multiple inheritance used for the mixin pattern. That multiple inheritance is severely limited because a protocol cannot add new instance variables to a class. A protocol only describes a public interface adopters must implement. Unlike Ruby modules it does not contain an implementation.

That's the most of it. Let's mention categories however.

A category is declared not in angle brackets, but between parenthesis. The difference is that a category can be defined for an existing class to expand it without subclassing it. You can even do so for a system class. As you can imagine, it's possible to use categories to implement something similar to mixin. And they were used that way for a long time usually as category to NSObject (the typical root of the inheritance hierarchy), to such an extent that they were called "informal" protocols.

It's informal because 1- no type checking is done by the compiler, and 2- implementing the protocol methods is optional.

There is no need today to use categories as protocols, especially because the formal protocols can now declare that some of their methods are optional with the keyword @optional or required (the default) with @required.

Categories are still useful to add some domain specific behavior to an existing class. NSString is a common target for that.

It's also interesting to point out that most (if not all) of NSObject facilities are in fact declared in a NSObject protocol. This means that it's not really compelling to use NSObject as a common superclass for all classes, though this is still commonly done for historical reasons, and well... because there is no drawback for doing so. But some system classes, such as NSProxy, are not NSObject.

Jean-Denis Muys
@jdmuys: This answer is very complete, but missed a tiny detail. I hope it's OK for you I took the freedom to add it.
Johannes Rudolph
damn! I was editing at the same time. I'm afraid your edit might have been lost. You can redo it! :-)
Jean-Denis Muys
@jdmuys: No problem. That's how (darwinist-) optimistic concurrency works here on SO :-)
Johannes Rudolph
Thanks for the answer, definitely cleared things up a lot
hacksignal
"A protocol only describes a public interface adopters must implement. Unlike Ruby modules it does not contain an implementation." - well, I think the whole point was that there's some code that one wants to reuse in various classes without reimplementing it, so using protocols doesn't help here at all...
Psionides
It's a matter of pattern. If you want to reuse some service from several otherwise unconnected client classes, then the right pattern is to define that service in its own class, which each client classes having an instance of the service classes in its ivars. Protocols are not for the case when you want to call a service, but rather for when you want to be called by a higher-order class. In my example, the singers are called whenever we want them to sing. If you need both, then a combination might work. And yes, having concrete protocols would be nice in Obj-C. Not yet.
Jean-Denis Muys