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.

Tagged , , , , , ,

Five years!

As of today, I’ve been with Apple for five years, working on developer tools.

It’s been great and I look forward to many more years of improving the experience for people creating great Mac and iPhone software!

Tagged , , , , ,

Go ahead and use Core Data

In a few weeks, it will be four years since Mac OS X 10.4 Tiger was first released. That was the first release to include Core Data. It will also be about one and a half years since Mac OS X 10.5 Leopard was released, with significant enhancements to the Core Data API.

It’s pretty safe to start using Core Data in your applications now. You certainly don’t need to wrote directly to the low-level SQLite API any more.

Tagged , , , , ,

No NSCoder Night for me tonight

Unfortunately I’m not feeling well, so I won’t be at NSCoder Night tonight. See everyone next week!

Tagged

Happy 25, Macintosh!

The Mac is 25 years old today.

Happy birthday, Macintosh. You’ve really changed the world.

Tagged

DDJ vs. Backyard Poultry

Eric Sink has a post talking about the sad state of developer publishing, specifically discussing the declining readership of the venerable developer magazine Dr. Dobb’s Journal, as compared to that mainstay of American newsstands Backyard Poultry.

After reading the article and the replies, I just had to throw in my two cents about magazine publishing and why “1% of the US population are software developers, so there should be a huge market for development magazines.”

It’s a significant mistake to think that the reader is the target and that the magazine is the product.

It is actually the aggregate readership that is the product, and the advertisers who are the target. That is, unless the magazine takes no advertising and is entirely supported by its subscribers.

This was driven home to me recently when I bought the recent “eInk Flashing Cover” issue of Esquire. I had never read Esquire before, so in addition to checking out the cool hardware on the cover, I started trying to read it. It was way more full of ads than Wired ever was — even in the days when Suck famously disassembled Wired 3.09 to remove the ads.

Furthermore, its advertisers were all very high-end. Thus I wasn’t that surprised when I saw that the price on the subscription card for a year of Esquire was well under $1/issue.

So if Dr. Dobb’s Journal is circling the drain, it’s not the current readership that’s to be blamed, or the Internet. It’s the lack of advertisers interested in reaching that readership, or the magazine’s ability to reach a readership that is interesting to a better-paying tier of advertisers.

Tagged ,

Let’s merge managed object models!

There was a question recently on Stack Overflow asking how to handle cross-model relationships in managed object models. Now, the poster wasn’t asking about how to handle relationships across persistent stores — he was asking how to handle splitting a model up into pieces such that the pieces could be recombined.

It turns out that this is somewhat straightforward to do using Core Data. Let’s say you have a simple model with Song and Artist entities. I’ll write it out here in a pseudo-modeling language for ease of reading:

MusicModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};

Now let’s say you want to split this up into two models, where Song is in one and Artist is in the other. You could just try and create two xcdatamodel files in Xcode, one with each entity, and wire the relationships together after loading them and merging them with +[NSManagedObjectModel modelByMergingModels:]. Except that won’t work: Relationships with no destination entity won’t be compiled by the model compiler.

What else might you try? You could try just putting dummy entities in for relationships to point to. However, merging models will fail then, because NSManagedObjetModel won’t merge models that have entity name collisions.

It turns out, though, that you can merge models very easily by hand, by taking advantage of the way Core Data’s model-description objects handle the NSCopying protocol. All you have to do is create your destination model, loop through every entity in each of your source models, and copy every entity that you haven’t tagged as a stand-in using a special key in their userInfo dictionary.

Why does this work? The trick is that before you tell a persistent store coordinator to use a model, that model is mutable and references relationship destination entities and inverse relationships by name. So you can have only a minimal representation of Artist in one model, and a minimal representation of Song in another model:

SongModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        /* Note no attributes. */
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { IsPlaceholder = YES; };
    };
};

ArtistModel = {
    Song = {
        /* Note no attributes. */
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { IsPlaceholder = YES; };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};

Then, when you write some code to combine them, the merged model will wind up with the full definition of Song and the full definition of Artist. Here’s an example of the code you might write to do this:

- (NSManagedObjectModel *)mergeModelsReplacingDuplicates:(NSArray *)models {
    NSManagedObjectModel *mergedModel = [[[NSManagedObjectModel alloc] init] autorelease];

    // General strategy:  For each model, copy its non-placeholder entities
    // and add them to the merged model. Placeholder entities are identified
    // by a MyRealEntity key in their userInfo (which names their real entity,
    // though their mere existence is sufficient for the merging).

    NSMutableArray *mergedModelEntities = [NSMutableArray arrayWithCapacity:0];

    for (NSManagedObjectModel *model in models) {
        for (NSEntityDescription *entity in [model entities]) {
            if ([[[entity userInfo] objectForKey:@"IsPlaceholder"] boolValue]) {
                // Ignore placeholder.
            } else {
                NSEntityDescription *newEntity = [entity copy];
                [mergedModelEntities addObject:newEntity];
                [newEntity release];
            }
        }
    }

    [mergedModel setEntities:mergedModelEntities];

    return mergedModel;
}

This may seem like a bit of overhead for this simple example. The critical thing to see above is that only that which is necessary for model consistency is in the placeholder entities. Thus you only need the inverse relationship from Song to Artist in ArtistModel. Say you wanted to add a Picture entity related to the Artist entity — you don’t have to add that to both models, only to ArtistModel. The benefit of this method for merging models should then be pretty apparent: It gives you the ability to make your model separable, just like your code.

Tagged , ,

Erlang on LLVM? or: Outsource your JIT!

Has anyone been working on using LLVM to do just-in-time code generation for the Erlang virtual machine?

Depending on the design and structure of the Erlang virtual machine, it doesn’t seem like it would be all that tough a project. And it could provide a nice performance boost for those projects that are starting to use Erlang like CouchDB and ejabberd.

For an example of what I’m talking about, there’s a project called VMKit that has implemented the Java and .NET virtual machines atop LLVM with reasonable performance. Essentially, if you have a virtual machine, rather than skipping either just-in-time or static code generation entirely, or trying to do it all yourself for some specific platform on which you want to run, take a look at what you can do with LLVM and see if you can leverage its code generation instead.

Tagged , , , , , , , , ,

Not it!

I didn’t write Carrie’s Dots — but I did download it!

It was written by Dr. Chris Hanson, a Chris Hanson who’s evidently still in the mid-South. Maybe the next time I get a chance to visit Mississippi, we’ll get to meet up!

Tagged , ,

LLVM terminology

I thought the proper terminology was worth pointing out, since I’ve seen — and heard — some misuses lately.

  • LLVM is the Low-Level Virtual Machine and the project surrounding it.

  • LLVM-GCC is a compiler that uses GCC for its front-end and LLVM for its back-end.

  • Clang is the C language family front-end that is part of the LLVM project. It’s a parser, semantic analyzer, and code generator — in other words, a compiler front-end that uses LLVM for its back-end.

  • The Clang Static Analyzer is what people have been trying out lately, to find subtle bugs in their and other projects. It’s a great tool.

I just thought this was important to mention, because people have been referring to “LLVM” instead of “LLVM-GCC” in reference to the compiler included in Xcode 3.1, and people have been referring to “Clang” instead of “the Clang Static Analyzer” in reference to what they’ve been using to find bugs in their projects.

Tagged , , ,