This is the last is a series of blog posts I’m writing on things that Objective-C can learn from Java. The other parts can be found here:
- Part 1 (Generics)
- Part 2 (Abstract Classes)
- Part 3 (Single Source File)
- Part 4 (Namespace)
- Part 5 (Exceptions)
For one who has programmed in other object oriented languages, Objective-C stands out with its complete lack of namespace. As a result, classes have a prefix, such as Apple’s common NS and UI prefixes. On the mac side of things, every class under the sun seemed to start with NS, such as NSString
, and confusion is added when on the iOS side, several classes start with UI, such as UIView
. This is due to the fact that without a concept of namespace, Objective-C cannot have two classes with the same name, regardless of whether the classes are public or not.
If I were designing an application which communicated on a network as well as talked to a database, I would split the two pieces into separate segments, or in Java, packages. Inside each package, I would likely have a Connection
class, which has completely different meanings within the network and database packages. Inside those packages, especially if the Connection
class was internal to the package only, I could name both classes Connection
without any concern and the code inside the package would immediately understand what Connection
actually meant. This is possible in Java because the actual class names are com.cod3r.app.network.Connection
and com.cod3r.app.database.Connection
. Since Objective-C does not have namespaces, I would have to name these NetworkConnection
and DatabaseConnection
.
Now, take the above scenario, and add another type of network connection. Then take that new network connection and add new specific case to it, making a new class. In Java, the package name gets longer where as in Objective-C the class name gets longer. I have run into cases where this borders on ridiculous if one wants the class name to define what it actually does without ambiguity. The class is within the Sapphire plugin. In the project, all classes had the prefix Sapphire
since it was a bundle included in another application and had to make sure there was never a class conflict. The project has the concept of a Directory
and a VirtualDirectory
was a directory which wasn’t associated with a directory in the file system. There is a type of VirtualDirectory
that was Custom
meaning it was defined by the user instead of already in the code. Finally, this particular class is responsible for importing these CustomVirtualDirectory
objects, making the final class titled SapphireCustomVirtualDirectoryImporter
. In Java, this class would have been Importer
within the net.nanopi.sapphire.directory.virtual.custom
package. The difference is the fully qualified classname would only be used in the import statement, and the short class name would be used in the code, instead of the really long classname used in every location as seen in Objective-C. This becomes particularly relevant when it comes to code completion that produces a terribly long list until nearly the entire class name is typed.
The lack of namespace becomes problematic when one uses third party libraries. Take the above Sapphire example and another plugin developer finds a completely unrelated library titled Sapphire. If that library happened to have a directory titled SapphireDirectory
, then both plugins cannot be loaded at the same time. Java goes even further with a two-level namespace such that two jars (bundles) with the same fully-qualified classname still don’t interfere since they are in separate jars.
Adding namespace is necessary for adding inner-classes, which Objective-C outright doesn’t use, but could in proper circumstances. Inner classes are useful for implementing delegate methods. When setting a delegate, one typically passed in the instance of an inner class rather than the current instance. Not adopting this model has the issue when a single class is set to be the delegate to multiple objects, such as being the delegate to two table views. Apple works around this design by making each delegate method have the first parameter be that of the object calling it’s delegate, such as the table view. This means if the code is different between the two, every single delegate method needs have an if statement to determine which table view is being processed, and eliminates the ability of one to skip implementing an optional method for one table but not the other. Both of these problems are eliminated with inner-classes. Finally, the lack of inner-classes severely cripples the ability of a super-class to use the Key Value Observing within Objective-C since the delegate and unregister methods were written in a way that really require an inner-class to work properly (I can see how to easily break some code in a sub-class or super-class since this was designed so badly).
Impact on Runtime: Small. I don’t know the specifics of the runtime, so I can’t judge the exact impact, but this will result in longer effective class names, which may increase lookup times. Inner-classes would need an instance variable for their outer-class to access it’s instance variables, resulting in additional pointer deference for accessing outer-class variables.
Impact on Code: No longer need to create necessarily long class names; programmer can use short class name without concern. Frameworks need not have a class prefix. More flexibility in object design.
Legacy Comments:
Fredrik Olsson - Sep 28, 2011
I am among the first to admit that prefixes is a poor mans solution to lack of namespaces. But that do not mean it is confusing or even without use. With the exception of old frameworks like AppKit and Core Data the use of prefixes is very predictable; its a marker for which framework that defines the symbol. Take for example UIColor, NSColor and CIColor (From UIKit, AppKit and Core Image respectively). If all three of them had been named Color as in Java it would not be obvious which type it is without scrolling to the top of the source code and look at the imports. Not knowing the framework of origin is generally not an every day problem. But knowing if a type is your own (or a colleges), or from a framework is.
Graham Booker - Sep 28, 2011
Fredrick, I’m afraid your opinion is tainted by the lousy IDE that is Xcode. First of all, the confusion comes into play when one is writing code and has to stop and think, “what framework is this class in again? Is it a CG or UI object?” In a real IDE, one would simply type the name, minus any prefix, and the code completion would show the options, with the framework path to which it belongs. Additionally, knowing the type of an object is quite simple in a proper IDE; the mouse-over text reveals the fully qualified class name. I say that Xcode is not a proper IDE because I have had to use it. It’s code completion often doesn’t work at all (just last week it never displayed anything for 2 hours straight despite hitting ctrl-space and F5 numerous times), and when it does work, it tends to show hundreds of completely irrelevant choices. Some of this is due to the language, which by its nature is not strongly typed, but that issue can be mitigated to a far greater extent that is currently.