What Objective-C can learn from Java, Part 1 (Generics)

Posted by Thoughts and Ramblings on Saturday, December 4, 2010

This is the first is a series of blog posts I’m going to write over the next several days on things that Objective-C can learn from Java. I’ve been programming in Java since 1997, and in Objective-C since 2001. The two languages have a lot of similarities, but there are a few design principles in which Java excels and Objective-C is left behind. This is understandable considering that Objective-C is older than Java, and Java borrowed heavily from Objective-C when it was designed. In this series I’m only going to discuss changes to the language; these items will have very little, if any, impact on the runtime. For the purposes of this discussion, I’m going to use Java’s terminology since it is more familiar with the programming public. This means I’ll talk about functions instead of selectors, and interfaces instead of protocols.

The other parts can be found here:

The first item which Objective-C can learn from Java is Generics. Objective-C is a weakly typed language, too weak for my tastes, whereas Java is strongly typed. There are distinct advantages to a strongly typed language, but I’m not going to get into that here. This means that Objective-C’s can make a function call on an object without knowing its type where as Java must have the object typed to an interface or class which defines that function. This requires typecasting in Java before making function calls, where as Objective-C does not. In some cases this throws a warning in Objective-C, and in some cases does not. Missing warnings can lead to programming mistakes, and programmer ignored warnings leads to bad style. In either case, typecasting will change the mistakes to warnings, and the warnings which are not mistakes to no warnings.

Java had the issue in requiring typecasting to make function calls. This lead to numerous typecasts in code, which added to clutter. Java’s solution to much of this clutter came through the use of generics. One of the largest sets of typecasts resulting in fetches from a collection. For example, if one had a list which contains objects of class Person, then it would be convenient if the complier just remembered that for you. This was done by simply declaring the list as List<Person>. Then, when fetching objects from the List, no typecast is necessary since the compiler already knows that all objects in that list are a Person in the first place. I should add, for the C++ programmers out there, this is not a template. Templates define a whole new set of code for that type, ballooning the object binary, where as generics can be thought of as automatic typecasting.

I have found many arguments that state Objective-C doesn’t need generics because it is a weakly typed language (just Google Objective-C generics to see them). These arguments tend to forget one major piece of the language. Consider the following code:

@interface Person : NSObject {
    NSString   *name;
    NSArray    *siblings;
    Person     *father;
    Person     *mother;
    NSArray    *children;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *siblings;
@property (nonatomic, retain) Person *mother;
@property (nonatomic, retain) Person *father;
@property (nonatomic, retain) NSArray *siblings;

@end

In this example, I’ve defined an Objective-C class called Person with a name, an array of siblings, a father, mother, and an array of children. Now, say I wanted to get the first-born child’s name. I could do this with [children objectAtIndex:0].name. Except, this produces an error because [children objectAtIndex:0] returns an id, not a Person *, and properties, unlike functions, are strongly typed in Objective-C. So, the recourse is to either use a temporary variable of type Person *, or to typecast on the same line like: ((Person *)[children objectAtIndex:0]).name. If Objective-C had generics, this would eliminate any need for the typecast or temporary variable since the compiler would already know the type of the object returned by the array.

This is a simple example of where generics become useful in the language, but there are far more. I have actually found Objective-C’s lack of generics limiting my ability to design class hierarchies, and requiring a large amount of unnecessary typecasts or in some cases, additional function calls, which produces slower code.

Should Objective-C adopt all of Java’s generics? I would contend the answer is no. Java’s generics can get very convoluted very quickly, and the biggest source of the mess is in defining a generic function call. While they add convenience, generics in function calls becomes very messy. However, generics on a class level (and used in it’s functions) add so much benefit and cleaner code design that Objective-C is really suffering without them. Additionally, Java produces warnings if a class containing generics does not have it’s generic type defined. For example, List children will produce a warning because I didn’t define the type of object contained within list. In these cases, since Objective-C is so weakly typed, it’d be most appropriate if its generics just defaulted to the base class allowed in the generic, which in the case of NSArray would be id.

Impact on Runtime: None, generics are syntax sugar only.

Impact on Code: Generics added where needed, changing the tracking of object type to the compiler instead of the programmer. Cleaner code, and less prone to error.


Legacy Comments:

Patrick - Sep 14, 2012

agreed