views:

229

answers:

7

I was hoping to make a list of some of the differences in terms between java and objective c to abate my confusion. It makes explaining my difficulties easier when I know what things are called.

For example:

  • null - nil
  • this - self
  • map - dictionary (not even quite sure about this one)

What I'm looking for are similar comparisons or corrections to ones I have listed. Not just limited to elements in the language, but concepts as well...

+2  A: 

Interface = Protocol

Field = Instance Variable ("ivar")

ArrayList = Array

call a method = send a message

The ones you have listed are correct.

Dave DeLong
+9  A: 

You're right about map = dictionary. I'll add:

  • @public, @private, @protected (the default) are for instance variables only (not methods) and work like C++'s visibility modifiers (i.e. you declare them as section headers rather than before each variable).
  • Class methods are like static methods in Java
  • There are only two data structures: NSDictionary and NSArray (in immutable and mutable variants). These are highly optimized and work well for most situations. For everything else, there's CHDataStructures
  • @interface doesn't work like Java's interfaces - it defines the instance variables and methods of a single class.
  • You need header files. C is to blame for this. This pretty much sucks, as maintaining the things is an unnecessary pain.
  • There is no concept of a "package". The closest thing is a framework, but these should not be used as Java's packages (i.e. don't create them just to organize your classes).
  • Instead of "new Class()", say [[Class alloc] init]. Think of "alloc" like the new operator and init as the constructor.
  • id's are generic object pointers, like references of type Object in Java.
  • The base class is NSObject. Inheritance from NSObject is not automatic and must be explicitly specified.
Ryan Ballantyne
+1 on CHDataStructures
Dave DeLong
Glad you pointed out the difference between `id` and `NSObject`, and how classes don't inherit from `NSObject` automatically.
htw
Class methods are fundamentally different from static methods, because class methods are dynamically dispatched and can be overridden by subclasses. The closest equivalent to a static method is a straight C function.NSObject is not _the_ base class, it’s _a_ base class. The most common alternative is NSProxy.Oh, and there’s also NSSet and NSCountedSet. :-)
Ahruman
+1 for the tip on conceptualizing alloc/init. Explaining the idiom to developers from other languages is always a bit tough. And thanks for recommending CHDataStructures — I'm glad people like it! :-)
Quinn Taylor
I've got a beef with the "alloc = new" and "init = constructor" point. See my answer about alloc and init.
Dave DeLong
I read "[[Class alloc] init]" can be wrote as "[Class new]", right?
Tim Büthe
+2  A: 

Off the top of my head:

  • Serialization = Archiving
  • Instance variables are usually accessed through properties instead of explicit get/set accessors. (In the old days, we used to write accessors too, but even then, they would usually be of the form foo/setFoo rather than getFoo/setFoo.)
  • An action/button/mouse/event listener is roughly equivalent to an IBAction, although the way GUIs are designed in Cocoa is quite different from Java.
  • Instead of just one class block, class definitions are defined by an @interface (for the instance variables and method declarations) and an @implementation (for the actual method code) directive.
htw
Although keyed archiving is much more robust than most serialization solutions in Java. :-)
Quinn Taylor
+3  A: 

Another conceptual difference is the behavior when calling methods (sending messages) on null objects (to nil).

Java

MyClass myObject = null;
myObject.doSomething(); <-- results in a NullPointerException

Obj-C

id myObject = nil;
[myObject doSomething]; <-- is valid

Here is a very good SO question about that behavior.

weichsel
Note: You only get a NullPointerException if "doSomething" isn't static.
Tim Büthe
A: 

Instead of using iterators for easy enumeration you typically use, for classes that implement the FastEnumeration protocol (interface in java), a simple

for( Class *element in container )

http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocFastEnumeration.html

groundhog
Since Java 1.5, there is a `for (Class element : container)` construct that works on anything that implements Iterable.
Quinn Taylor
+2  A: 

Previous answers cover most of the "phrasebook" differences, but there are a several key conceptual differences that bear mentioning... (Note that I only mention pure Objective-C issues, not Cocoa.)

  • There is a flat namespace for classes, and one for protocols. There is no such thing as packages or package hierarchies. All class names must be distinct (and all protocol names must be distinct) in an application. This is generally accomplished by using ~2-letter prefixes.
  • Exceptions are reserved for exceptional flow, almost always as the result of programmer error. The purposes for which 95%+ of Java exceptions are better served by returning an NSError if needed.
  • Consider using categories instead of one-off subclasses, but both should be done judiciously and cautiously. (Categories make the inheritance hierarchy less constrained, but affect all instances of a class. They're often a solid choice when you would normally subclass, such as for UI elements.) Frequently (in both Objective-C and Java) the best solution is to use composition instead.
  • You can use dynamic typing nearly everywhere as desired, just be aware that it is a double-edged sword. It gets rid of the need for a lot of casts, but errors that would be caught at compile time in Java are pushed to runtime in Objective-C. Static typing can be used anywhere as desired, and provides greater compile-time safety. (Java developers often view non-static typing as a language deficiency, but would do well to understand the flexibility it makes possible.)
  • You can mix C functionality and libraries freely without JNI wrappers. But you also get all the cruft and limitations of straight C. Yes, it would be wonderful if we could do away with the need for header files, but it's just not going to happen for C-based languages. Life isn't always fair. :-)
Quinn Taylor
+1 for the bit about exceptions, which I hadn't considered.
Ryan Ballantyne
+2  A: 

A philosophical answer about alloc/init.

init is not a constructor. Conceptually, "construction" does not exist in Objective-C. In Java (and other languages with constructors), calling the constructor will return a new instantiation of the object that is ready to go. There is no exact equivalent to this in Objective-C. (One could argue that convenience class methods such as +array, +arrayWithObjects, etc are technically constructors since they wrap both allocation and initialization, but I would argue that they're still not constructors in the same sense as Java constructors.)

What we have instead is the concept of allocation and initialization, two distinct steps that, when executed together, act as if they were a "constructor". The class method +alloc simply requests an appropriately sized chunk of memory from the system. IIRC, it uses the calloc() function to do so. It is not guaranteed that any zeroing will take place during the execution of the alloc function. This means that we need to do the initialization ourselves, which we do by immediately calling an -init method.

HOWEVER, -init (and all derivatives) are nothing more than ordinary instance methods. You can message them whenever you want in order to "reset" an object instance to its original initialized state (although there are some memory management ramifications of doing this that must be taken into account). It also means that you can do something ridiculous like this:

NSUInteger count = [[[NSArray alloc] autorelease] count];

I can't think of a good reason why you'd want to do this, but the point is that you can. It further goes to emphasize that init is not a constructor. In the example above, the object exists by the time the +alloc method returns. However, it may not be properly initialized, which means that the unsigned integer "count" might not be zero. It could be, but it would be incorrect to rely on that behavior (unless otherwise documented, of course).

One of the advantages of breaking construction into allocation and initialization is we can have a large degree of control over exactly what's getting initialized. In Java, for example, you can only have one constructor per method signature. In other words, if you have a constructor that takes a single "Object" argument, then that's the only constructor that can. You cannot create another constructor that also takes a single Object argument.

In Objective-C, parameter types are not part of the method signature (known as a "selector"), and so I can create an initializer like so:

- (id) initWithAnObject:(id)anObject;

However, I can also create another initializer:

- (id) initWithADifferentObject:(id)anObject;

I can set these up to do totally different initializations of the object on which they're invoked. This is unbelievably useful!

Another really useful aspect of splitting construction into allocation and initialization is that you can chain initializers. AFAIK, you can't call constructors from within constructors in languages like Java (well, you can, but it doesn't have the same effect). In Objective-C, however, you can do something like this:

- (id) initWithCapacity:(NSUInteger)initialCapacity {
  if (self = [super init]) {
    [self setInitialCapacity:initialCapacity];
  }
  return self;
}

- (id) init {
  return [self initWithCapacity:0];
}

Now when you alloc/init an object set up like this, it will "redirect" and use the initWithCapacity initializer, even though you called init. (This is how NSArray's init method works) This means you can use conditional initializers. For example, have your -init method dispatch to one initializer under certain conditions but use a different one under different conditions.

In summary, the Objective-C model of "allocate and initialize" is much more powerful than the idea of construction. You, as the programmer, have a much greater degree of control over the initial setup phase of your object. It is a really liberating shift.

Cheers,

Dave

ps - init is not a constructor! ;)

Dave DeLong
That was very useful. Thanks!
Jeff Barger
I stand behind my comparison. The new operator semantically acts as an allocator, and the constructor as an initializer. Constructors don't allocate memory either - they get objects ready to go, just like init methods do. Yes, the details differ (and I learned some things from your post), but that's to be expected since they're quite different languages. That doesn't mean the comparison is without value.
Ryan Ballantyne
Also, I consider convenience methods like +arrayWithObjects to be closer to Java factory methods than Java constructors. :)
Ryan Ballantyne