Cocoa for Scientists (Part V): It's All in the Genes
Author: Drew McCormack
Website: http://www.macanics.net
Last time we discussed the life cycle of an object in an Objective-C program — how it is created and when it is destroyed. In this installment, and the next one, we will look at the blood line of an object or class; how it relates to its ancestors in the inheritance tree, and how descendants can substitute for their forebears. These aspects of Object-Oriented Programming (OOP) are known in the jargon as inheritance and polymorphism.
These two tutorials will be the last in the series dealing solely with Objective-C. We will then move into Xcode, and start looking at building graphical interfaces, which is what Cocoa is really all about. There are still parts of Objective-C that we have not dealt with, but these will be handled inline during the rest of the series, as they arise.
The Blood Line
We have already come across class inheritance several times in this series, and have tended to gloss over it somewhat. Here, we will look in more detail at how it works in Objective-C, and how that differs from various other programming languages which you might be familiar with.
A class inherits from another class in Objective-C when it includes that class in its interface block, like this
@interface AdditionOperator : Operator {
}
@end
In this example, AdditionOperator inherits from Operator. That entails that AdditionOperator includes all of the instance variables and all of the methods that are defined in the Operator class, or any ancestor thereof. So if Operator in turn inherited from NSObject, AdditionOperator would also include all the instance variables and methods that are included in NSObject.
To demonstrate this, take a peak at this code:
#import <Foundation/Foundation.h>
@interface Operator : NSObject {
NSArray *subExpressions;
}
-(id)initWithSubExpressions:(NSArray *)newSubExprs;
@end
@interface AdditionOperator : Operator {
}
-(unsigned)numberOfSubExpressions;
@end
@implementation Operator
-(id)initWithSubExpressions:(NSArray *)newSubExprs {
if ( self = [super init] ) {
subExpressions = [newSubExprs retain];
}
return self;
}
-(void)dealloc {
[subExpressions release];
[super dealloc];
}
@end
@implementation AdditionOperator
-(unsigned)numberOfSubExpressions {
return [subExpressions count];
}
@end
int main() {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
AdditionOperator *op =
[[AdditionOperator alloc] initWithSubExpressions:[NSArray array]];
NSLog(@"The number of subExpressions are %d", [op numberOfSubExpressions]);
[op release];
[pool release];
return 0;
}
You can build this example by entering it into a file (eg test.m) and compiling with this command:
gcc -ObjC test.m -framework Foundation
Run it by entering
./a.out
The output should resemble this
2006-12-27 13:55:52.216 a.out[3663] The number of subExpressions are 0
This is a somewhat phony example, because the method numberOfSubExpressions would normally be declared and defined in the Operator class rather than the AdditionOperator class, but it does demonstrate inheritance. AdditionOperator does not directly declare any instance variable called subExpressions, as you can see in the AdditionOperator interface block, but it does make use of this variable in the numberOfSubExpressions method. The AdditionOperator includes the subExpressions instance variable because it inherits it from Operator. The variable can be accessed just as if it were defined directly in the AdditionOperator interface block.
The same is true of the methods in the Operator class. The initWithSubExpressions: initializer method, for example, is used to initialize the AdditionOperator object, but it is declared and defined in the Operator class. What’s more, the release method called on the AdditionOperator object actually descends from the NSObject class.
Access Control
You can actually apply constraints on the accessibility of instance variables in Objective-C, as in most object-oriented programming languages. The default, which we have been using to this point, is @protected, which means that an instance variable can be accessed from within the class in which it is defined, and from any descendent (eg subclass). The other two options are @private, which restricts access to the defining class, excluding its descendent classes, and @public, which allows free-for-all access from anywhere in the program. (This is generally not a good idea, as we will discuss below.)
To test these keywords, change the Operator class definition above to this:
@interface Operator : NSObject {
@private
NSArray *subExpressions;
}
-(id)initWithSubExpressions:(NSArray *)newSubExprs;
@end
If you now try to compile, you should get this error message:
test.m: In function ‘-[AdditionOperator numberOfSubExpressions]’:
test.m:38: error: ‘subExpressions’ undeclared (first use in this function)
test.m:38: error: (Each undeclared identifier is reported only once
test.m:38: error: for each function it appears in.)
The reason for this error is that the @private keyword restricts direct access to the subExpressions instance variable to the immediate class, ie Operator. So when the numberOfSubExpressions method of AdditionOperator attempts to access the instance variable, a compile time error arises.
The flip side of private is public. If you again change the Operator interface block, as follows
@interface Operator : NSObject {
@public
NSArray *subExpressions;
}
-(id)initWithSubExpressions:(NSArray *)newSubExprs;
@end
you can then access subExpressions from outside the class hierarchy. For example, you could change the main function to
int main() {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
AdditionOperator *op =
[[AdditionOperator alloc] initWithSubExpressions:[NSArray array]];
NSLog(@"The number of subExpressions are %d", [op->subExpressions count]);
[op release];
[pool release];
return 0;
}
Note that in this case, instead of calling numberOfSubExpressions, direct access is made to the op->subExpressions instance variable.
If you have experience in Object-Oriented Programming (OOP), it may come as a surprise to you that Objective-C does not include any similar access control for methods, which is the case in languages like C++ and Java. In Objective-C, all methods are effectively public, that is, they can be called from any part of the program. You can fake a private method by declaring it not in the public header file, but in the .m implementation file. You can do this, because Objective-C has something called categories — basically, you can declare multiple interface blocks for a single class.
To show this, imagine we wanted — for reasons unknown — to keep the numberOfSubExpressions method private, such that it could only be used in the AdditionOperator class. You could do this by placing the main interface of AdditionOperator in an AdditionOperator.h header file, moving the implementation to AdditionOperator.m, and then declaring a category in AdditionOperator.m like so
@interface AdditionOperator (Private)
-(unsigned)numberOfSubExpressions;
@end
At the same time, you would remove the numberOfSubExpressions declaration from the main interface block. The category name Private is arbitrary, but must be unique for the AdditionOperator class.
The net effect of this is that any code that includes the AdditionOperator.h file will no longer see the numberOfSubExpressions declaration, and you will get a compiler warning that the method was not found. Note that this will be a warning, not an error, but you should take heed of it, or be prepared to face a gruesome end.
Controlling access to instance variables and methods forms an important part of what is known in the OO lingo as data hiding. Basically, you attempt to guarantee the validity of your data by only accessing it from a localized region of your program (eg, a class and its descendents). Any external changes to that data proceeds indirectly via accessor methods — which were discussed in a previous tutorial — so that the sanity of the changes can be strictly controlled. Using data hiding greatly reduces the dependencies in your programs, making them easier to understand, and making it much easier to locate problems should they arise.
Protocols
If you have ever programmed in Python or C++, you will be aware of multiple inheritance. This is when a class inherits not from one class, as above, but from many. Objective-C does not support multiple inheritance. Depending on who you talk to, this is either a good thing or a bad thing. In general though, only having single inheritance does make it easier to understand a program.
Objective-C does have a construct to support some of the advantages of multiple inheritance, without suffering the complexity: protocols. Protocols are blocks that declare one or methods that a class must implement. When a class conforms to a protocol, it has to implement the methods in the protocol. There is no limit on the number of protocols that a class can conform to.
Java programmers will already be familiar with protocols: they are basically the same as interfaces in the Java language. Protocols are a bit like a superclass without the instance variables; they can only define what methods a class has to have, but cannot include any data, or indeed, any method implementation. Here is the basic syntax of a protocol
@protocol Add
-(id)add:(id)toAdd;
@end
The Add protocol says that any conforming class must have a method called add: with the signature given. Imagine that we wanted to make AdditionOperator conform to the Add protocol; the interface block would look like this
@interface AdditionOperator : Operator <Add> {
}
@end
and the implementation block would include an implementation of the add: method
@implementation AdditionOperator
-(id)add:(id)toAdd {
// Implementation here
...
}
@end
It may not be clear to you yet why you would want to have protocols. What purpose do they serve? I’m afraid you will have to wait for our next installment, dealing with polymorphism, to fully appreciate protocols.
Working with Your Ancestors
Inheritance is often said to allow for ‘programming the changes’. What this means is, instead of rewriting a whole section of code whenever a small change in behavior is required, you can simply create a subclass and override the appropriate methods.
When a subclass has a method with the same signature as a method in an ancestor, the subclass method is used. Basically, Objective-C messaging works something like this:
- You call a method (send a message) to an object
- The Objective-C run-time system looks to see if the method exists in the object’s class
- If not, it moves up to the superclass, and looks there.
- It repeats this search, until the method is found, or until there are no classes left in the inheritance tree.
(This may seem like it would be a very slow process, and relative to a function call, it is, but by using advanced caching, it is only really too slow for the most performance intensive tasks. For example, you shouldn’t try to do matrix multiplication by making a method call for each element.)
So overriding allows you to change the behavior of a class through subclassing, by reimplementing one or more of its methods. Note that this doesn’t mean you have to rewrite everything in the overridden method, because — as we have already seen a few times in this series — you can invoke methods in the superclass using the super pointer.
Let’s imagine that you want to have the AdditionOperator class log some output whenever the numberOfSubExpressions is invoked, but that you don’t want to change the AdditionOperator class itself. You could create a subclass, LoggingAdditionOperator, and override the numberOfSubExpressions method:
@interface LoggingAdditionOperator : AdditionOperator {
}
@end
@implementation LoggingAdditionOperator
-(unsigned)numberOfSubExpressions {
NSLog(@"numberOfSubExpressions invoked");
return [super numberOfSubExpressions];
}
@end
The new implementation of numberOfSubExpressions uses the Cocoa NSLog function to write a string to standard output. It then chains to the numberOfSubExpressions implementation in the AdditionOperator class. In this way, the implementation of numberOfSubExpressions has been changed a bit, without the need to completely rewrite it.
There are some subtleties of inheritance that may not be immediately obvious to someone new to OOP. One of these subtleties is that inheritance allows you to extend a class, by introducing a subclass with extra methods, or change a class’ behavior, by introducing a subclass and overriding methods, but it does not allow you to remove functionality. If a method is defined in a class, you cannot remove that method in a subclass. To put it another way: anything the superclass can do, the subclass can do too.
Incestuous Inheritance
To finish off this little foray into inheritance, I want to issue a few warnings. When programmers first learn OOP, they are inclined to use inheritance for everything. Overuse of inheritance can actually be a bad thing, and here’s why: Classes that inherit from another have a tight coupling. Change one, and you generally change the other. If an inheritance tree gets very deep, it can become difficult to see the forest for the inheritance trees. It’s hard to find where methods are defined, and the various relationships between classes.
Often, when it seems like inheritance could be used, a better solution is to use association. That is, instead of making one class inherit from another, simply write classes that are not related by inheritance, but that hold references/pointers to one another. That way, the functionality in one class can be used from another class, without the complication of inheritance.
Inheritance should represent ‘is-a’ relationships. A Doctor is-a Person. An AdditionOperator is-a Operator. Association, on the other hand, represent ‘has-a’ or ‘makes-use-of’ relationships. A Plane has-a Wing. A Engine makes-use-of a Piston. Saying these little phrases to yourself should clarify whether inheritance is appropriate, or whether you should stick with association. When in doubt, err on the side of association.
A Good Inheritance
The warnings above are not intended to prevent you from ever using inheritance, but rather to prevent you from overusing it. There are times when inheritance is very powerful, in particular when combined with polymorphism, which will be the subject of our next tutorial. Until then, keep evolving.



Comments
Scientist Specific?
Thanks for another great installment of this tutorial. Any chance later issues could focus on specific classes or APIs useful to scientists? For example, I know somebody out there has made a great linear algebra object for Cocoa, but I've never found one (nor do I know where to start looking). If such tools were general enough and fast enough they could rival applications such as Matlab, but with far greater flexibility, power and room for creativity.
Again, thanks for your work
Justin
Be patient ;-)
I am planning to make the examples I introduce as 'scientific' as I can. Linear algebra, plotting, tabulated data — I intend to cover it all. But before we can do all that fun stuff, there needs to be a bit of background on Objective-C, which is not really scientific. I am trying to contrast Obj-C with languages that scientists may already know, but we haven't really have a decent sized example yet to demonstrate scientific programming in Cocoa.
Rest assured, it's coming. Just one more installment of Obj-C, and we will be into Xcode and scientific apps (albeit simple ones).
Regards,
Drew
---------------------------
Drew McCormack
http://www.macanics.net
http://www.macresearch.org
This tutorial is-a cool thing!
Thanks again, in particular for the 'is-a' and 'has-a' hint. That really helps.
Great!
Me too, I'd like to thank you for this great tutorial!
I've read quite some in the fast few weeks, but yours is perfect - short enough, easy to read but nevertheless covering about all I want to know and even answering some questions which arose when I followed other tutorials.
Thank you!
Private & Protected
Coming from JAVA & C#: If I want to declare a class method as private in objective-C - I cannot do that ? If I cannot that means the concept of encapsulation or data hiding is missing ? Can you clarify this please? Thanks
Private methods in Cocoa
The way you usually make a method private in Cocoa is simply not to put it in the header file. You can make a Objective-C category in the the .m file for private methods:
@interface MyClass (PrivateMethods)
-(void)thisOldMan:(id)man hePlayedTwo:(NSNumber *)two;
@end
To mimic protected methods, do the same, but in the header. The compiler won't enforce it though; it is only a convention, and developers must abide by it. (Lots of Obj-C is about convention over configuration.)
@interface MyClass (ProtectedMethods)
-(void)thisOldMan:(id)man hePlayedTwo:(NSNumber *)two;
@end
Drew
---------------------------
Drew McCormack
http://www.maccoremac.com
http://www.macanics.net
http://www.macresearch.org
Private methods
To add to Drew's response, the method can still be called at runtime from any place in the code, even if the method is made 'private'. If the method is not in the public header and is used outside of the class, the compiler will simply generate a warning, but the app will not crash or generate an exception at runtime. This is because method calls are dynamic and resolved only at runtime.
Great tutorial!
I really like that you don't overstress the fact that ObjC does not have private methods. It is quite a bit of a downside, but people learning a new thing should not feel stressed about stressed about what the language is missing when they are still trying to learn what it has to offer.
I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones.
- Albert Einstein