Skip to content

When to use properties & dot notation

I listened to a recent episode of the cocoaFusion: podcast about properties and dot notation today. There were a few interesting points brought up, but I felt a couple of the most important reasons to use @property declarations and dot notation weren’t addressed.

The biggest reason I see to use a different notation for both property declaration and property access than for method declaration and sending messages — even if property access ultimately results in a message send, as it does in Objective-C 2.0 — is separation of state and behavior.

In the ur-OOP days of Smalltalk, state was supposed to be encapsulated within objects entirely. This has become Smalltalk dogma and some developers have tried to propagate it to Objective-C: The idea that objects should never expose their state to each other, but instead only vend behaviors. It makes a certain amount of sense if you see objects purely as actors.

However, in today’s modern world we understand that objects aren’t just actors. Objects both “do things” and “represent things;” they’re nouns. And they have both internal state that they use in managing their behavior and external state they expose to the world.

You can use the same mechanism to do both, as Smalltalk does and as Objective-C did before 2007. However, it turns out that it can make a lot more sense to use different syntax to represent the distinct concepts, even if they’re handled by the same underlying mechanism.

For example, I might have a Person class and an NSViewController subclass that presents a Person instance in a view. The API to my Person class might look like this:

@interface Person : NSObject
@property (copy) NSString *name;
@property (copy) NSImage *picture;
@end

This sends a strong signal to the users of the class that name and picture are external state for a Person instance, leading me to write code like this:

Person *person = [[Person alloc] init];
person.name = @"Chris";
person.picture = pictureOfChris;

The intent of this code is clear: I’m not asking person to do anything, I’m just manipulating its external state. That may cause it to do things as a side-effect, but at least in the code snippet I’m looking at, I’m just interested in changing some state.

Now let’s see what the NSViewController might look like:

@interface PersonViewController : NSViewController
@property (retain) Person *person;
- (BOOL)updatePicture;
@end

And let’s see how I’d use one, assuming it’s been instantiated and wired up in my view hierarchy already:

selectedPersonViewController.person = person;

if ([selectedPersonViewController updatePicture]) {
    // note elsewhere that the person's picture is updated
}

Even though the -updatePicture method has no arguments and returns a BOOL I (1) don’t make it a property and (2) don’t use dot notation to invoke it. Why not, since it fits the form of a property? Because it doesn’t fit the intent of a property. I’m actually telling the view controller to perform some action, not just changing some state, and I want the intent of that to be clear to a reader of the above code.

That brings me to the other major reason to both declare properties using @property and use dot notation to access them: Xcode. The code completion technology in Xcode tries hard to provide you with a good default completion and good choices in the completion list. But this can be very difficult, especially with the combination of Objective-C’s dynamic dispatch and the sheer size of the frameworks: There are hundreds (!) of methods declared in categories on NSObject as a result of categories describing informal protocols, and any of those methods could be valid on an arbitrary instance.

Dot notation, on the other hand, is not valid on arbitrary objects. Even though it compiles to exactly the same sort of objc_msgSend dynamic dispatch that bracket notation does, from a type system perspective it actually requires a declaration of the property being accessed to work correctly. The reason for this is that the name of a property is not necessarily the name of the message selector to use in dispatch; think of a property hidden whose underlying getter method is named -isHidden.

This means that tools like Xcode can provide a much more streamlined experience for properties using dot notation. If I write the above code in Xcode, rather than MarsEdit, Xcode will not offer completions like -autorelease and -retainCount when I type person. — it will only offer me the properties it knows are on Person.

Now, you can invoke arbitrary getters or setters (so long as they have a corresponding getter) using dot notation. The compiler doesn’t require an @property declaration for the use of dot notation, just a declaration. I could have declared the Person.name property like this:

@interface Person : NSObject
- (NSString *)name;
- (void)setName:(NSString *)value;
@end

The compiler will compile person.name = @"Chris"; just fine with this declaration, to an invocation of -[Person setName:] — but Xcode won’t offer you code completion for it if you don’t use @property to declare it. By not offering to complete non-@property properties for dot notation, Xcode avoids offering you bad completions like autorelease and retain that are technically allowed but are abominable style.

Of course, one complication is that many frameworks on Mac OS X predate @property declarations and thus don’t expose their state this way. That means Xcode won’t offer you completions for their state with dot notation until those frameworks do. Fortunately for iPhone developers, UIKit uses @property declarations pervasively. You should too.

To sum up:

  • Use @property to declare the state exposed by your objects.
  • Use dot notation to get and set objects’ state.
  • Use method declarations to declare the behavior exposed by your objects.
  • Use bracket notation to invoke objects’ behavior.

This results in intention-revealing code that clearly separates state and behavior both in declaration and use.

{ 18 } Comments