views:

321

answers:

5
+11  A: 

First, you need to understand that you're making a classic mistake: that the language you already know defines the terms used in all languages - as if a particular language has established a canonical nomenclature.

Java was begun in 1990 internally at Sun. Objective-C had already been released in 1986. So, if anything, Java's interface terminology is at odds with Objective-C, not the other way. However, interface has a lot longer history as a term than either of these languages.

The idea behind the @interface in Objective-C is outlined in the Objective-C 2.0 Programming Language Reference:

interface Part of an Objective-C class specification that declares its public interface, which include its superclass name, instances variables, and public-method prototypes.

instance methods are class methods are public if they are declared in the interface. if they are declared in the @implementation they are private.

The implementation goes into the @implementation. Perhaps what is confusing you is that Java doesn't have the notion of a class declaration section like in Objective-C. The class declaration declares the class interface in a generic way, without specifics of the implementation. The @implementation has the actual implementation, which is the details of how the class @interface is implemented.

It's not wrong that objective-c is different than Java, it's just different.

But you're right, protocols are the closest analog to java interfaces in objective-c you're going to find. It isn't a superclass for anything, and doesn't have any associated implementation. You provide protocols much as you would interfaces in Java.

However, notice that protocols are not as common as classes in Objective-C. That should help guide your thinking.

groundhog
I'm sorry if I came off as comparing Objective-C to Java. That wasn't my intent. The word Java never appeared in my original post. I was simply stating my internal conflict about what I consider to be an interface and what Objective-C considers to be an interface.The advice of just do what the other code does doesn't exactly sit well with me internally but it does have some merit. When in rome etc... Gives me something to think about.
Well, your user of the term "interface" in the way Java uses it shows an understanding based on Java's terminology and concepts, but aren't necessarily valid outside of Java's conceptual framework.Studying languages is a tremendously useful exercise - learn to appreciate the intellectual variances to inform your use of other languages.
groundhog
(I didn't think the asker was directly pitting Obj-C against Java, but you're correct that there were some overtones that suggested confusion due use of terminology in the two languages.) Objective-C was actually invented in 1982, and I found it very interesting when I discovered that Objective-C had a non-trivial influence on Java — http://www.virtualschool.edu/objectivec/influenceOnJava.html
Quinn Taylor
+10  A: 
e.James
Nice answer, especially for addressing the OP's question about private instance variables in the header file. Just adding a link to another SO question about that particular issue: http://stackoverflow.com/questions/966893/why-are-instance-variables-defined-in-the-header-file-in-objective-c
Jarret Hardie
Objective-C is a really thin layer over C. It's really just managing a few symbol tables during the compile; very similar to the c preprocessor itself. I'm sure most of the decisions were to make coding it easier (like using square braces instead of parens, they had to find something they could easily parse and extract from the surrounding code. Probably the reason they chose to follow the Lisp syntax as well--easier to parse/extract/replace. Neat hack though. I think the header file is input only, not just a symbolic replace, so that's probably why they put variables there.
Bill K
They were not following the Lisp syntax, but rather the Smalltalk syntax. Smalltalk tries to handle as much as possible (including conditional statements) through uniform use of message passing, and the syntax reflects this design principle by basically consisting of nested blocks.
Felixyz
+3  A: 

No-one has yet explained why instance variables appear in the @interface of an Objective-C class. Objects are implemented as C structures which contain the instance variables. When you create a new subclass, a new type of structure is defined with all the superclass's ivars followed by the new class's ivars. The superclass structure must contain the ivars of its superclass, and then it's "turtles all the way down" to a structure which represents the ivars of the base class.

In the case of NSObject (and indeed Object), the base class structure only contains one ivar - a pointer called isa to the Class structure representing this object's class. So if I wanted to subclass it like this:

@interface GLObject : NSObject {
  int x;
}
@end

I need to know how to make a structure which looks like:

{
  Class isa;
  int x;
}

therefore the ivar layout of the parent class (and by induction any class) needs to be part of the class's public contract, i.e. part of its @interface. It may not be pretty, but there it is.

Graham Lee
In point of fact, this is no longer true in the non-fragile runtime (64-bit Mac OS X and iPhone), which doesn’t use fixed layouts. When building for the non-fragile runtime, you can implicitly add ivars in the @implementation using the @synthesize directive. There is no technical reason not to allow a {} ivar block in the @implementation; word is that this was left out purely for reasons of time. Bugs have been filed.
Ahruman
Right, too true. There is no technical necessity since the @interface is used to inform the compiler of the necessary types and membership when compiling source which references the class without causing dependency on the implementation. If an ivar is @private, there is no real compelling reason for its existence in the @interface block other than syntax.
groundhog
@both commenters: right. I thought introducing multiple runtimes at this point wasn't quite appropriate ;-)
Graham Lee
+1  A: 

I've also realized there is nothing really forcing my public facing interfaces to contain instance variables...

@interface Foo : NSObject
// some methods but no ivars
+ (Foo*) fooWithBlahBlah
@end

And the implementation file...

@implementation Foo

+ (Foo*) fooWithBlahBlah {
    return [[SomeDerivedFoo alloc] init];
}

@end

Where SomeDerivedFoo is declared internally not visible to clients...

@interface SomeDerivedFoo : Foo
{
    // instance vars
}
// overrides of methods

This would allow the component to expose an interface free of ivar dependencies. In fact this is the model that I see in so called "Class Clusters". This "feels" alot better to me.

My big problem with ivars in the public interface is all about dependency control. If my ivars are nothing but other Objective-C classes then yes I can get away with forward declarations but in the case of embedded C structs or other non class types I have to see the definition of those types and so my clients are now dependent on them.

Changing an instance variable should not cause clients of my interface to recompile. A relink is fine but not a recompile. In the case of a shared framework not even a relink should be necessary. This has nothing to do with any particular language. It has to do with isolation from details. That's a pretty universal goal in my mind.

This is what led to my original question about protocols vs interfaces. It seems that for a library or framework the more "correct" thing to do is to provide a set of protocols along with some sort of "Provider" or "Factory" classes to vend implementations of those protocols.

+1  A: 

An alternative if you're not able to support the 64-bit runtime and exclusively synthesise ivars, is to make an id ivar in your class. If you need to return to your class after shipping and add more instance variables, you can use this id as a container for them.

This allows you to write less complex code, while giving you some leeway to change things behind your client's backs without forcing a recompile.

By typing the ivar as id you're not promising anything to client code (an it should be made @private anyway).

I would imagine having all your public classes act as proxies to private implementations would get a little unmanageable. Keep in mind, if you do, you can use runtime forwarding to reduce the amount of code you have to write in the public class. See -[NSObject forwardingTargetForSelector:]. It's documented in the 10.5 Foundation Release Notes

Jonathan Dann