For a long time (including the entire development of touchDefense), I was against the concept of Objective-C 2.0. Not that I hate changes, but it seemed a bit arbitrary for Apple to take it on itself to modify Objective-C. Certainly no other company has the same level of investment in ObjC, but Apple doesn't have the same legal stranglehold on ObjC that Microsoft has on .NET languages. It just felt a bit wrong to me.
But when I began working on my newest iPhone application, I decided to go ahead and make the transition to writing my code using the syntactic confections sold at the Objective C 2.0 bakery.
Ideologies be damned, I'd rather fill up on gas in West Virginia again than write another unnecessary mutator or accessor methods. From a long-time anti-ObjC 2.0er, these are the reasons I decided to gorge upon the sweet syntatic sugar.
@property. @property. @synthesize.
I don't like the idea of properties, which strikes me as creating unnecessary ambiguity about what you're actually doing1. But, I do love not having to type as much boilerplate code.
Using properties is pretty easy. Take this ObjC 1.0 interface:
@interface Person : NSObject {
NSString * name;
int age;
NSMutableArray * friends;
}
-(void)setName: (NSString *)aName;
-(NSString *)name;
-(void)setAge: (int)anAge;
-(int)age;
-(void)setFriends: (NSMutableArray *)someFriends;
-(NSMutableArray)friends;
@end
which has this implementation:
@implementation Person
-(void)dealloc {
[self setName:nil];
[self setFriends:nil];
[super dealloc];
}
-(void)setName: (NSString *)aName {
if (name != nil) [name release];
name = [aName copy];
}
-(NSString *)name {
return name;
}
-(void)setAge: (int)anAge {
age = anAge;
}
-(int)age {
return age;
}
-(void)setFriends: (NSMutableArray *)someFriends {
if (friends != nil) [friends release];
friends = [someFriends retain];
}
-(NSMutableArray)friends {
return friends;
}
@end
Now that isn't really that hard to write, but after you've written it a hundred times you're probably had enough. Using ObjC 2.0 and properties you can rewrite the interface to look like this:
@interface Person : NSObject {
NSString * name;
int * age;
NSMutableArray * friends;
}
@property(readwrite,copy) NSString * name;
@property(readwrite,assign) int age;
@property(readwrite,retain) NSMutableArray * friends;
@end
But the real win is for the implementation:
@implementation Person
@synthesize name, age, friends;
-(void)dealloc {
[self setName:nil];
[self setFriends:nil];
[super dealloc];
}
@end
Ahhh. That's so much shorter. We do still have to write a dealloc method2, but we've compressed a dozen lines of tedious code into one, and that's a real win for me.
Beyond magically creating mutators and accessors, you can also use attributes as an abbreviation for a field's mutators and accessors. Some people may find this to be useful, but to me it seems at best neutral, and didn't weight strongly for my switching to 2.0.
// is this
Person * p = [[Person alloc] init];
p.name = @"Will";
p.age = 23;
p.friends = [[[NSMutableArray alloc] init] autorelease];
NSLog(@"Person(%@, %d, %@)",p.name,p.age,p.friends);
// really better than this?
Person * p = [[Person alloc] init];
[p setName:@"Will"];
[p setAge:23];
[p setFriends:[[[NSMutableArray alloc] init] autorelease]];
NSLog(@"Person(%@, %d, %@)", [p name],[p age],[p friends]);
I don't buy it. Not saying it's worse, but I think that one Swiss Army chainsaw is enough, thank you.
I like Iterators, too.
After properties and synthesize, my next favorite addition has to be iterators. I'm glad the genius of Perl, Python, Ruby, Java 1.5--pretty much every language in heavy usage--has come to Objective-C.
In lines of code, the difference between
int i, int l = [people count];
for (i=0; i<l; i++) {
Person * p = [people objectAtIndex:i];
NSLog(@"age: %d", [p age]);
}
and
for (Person *p in people) {
NSLog(@"age: %d", [p age]);
}
is pretty minimal. But I think it's a huge improvement. First, manually iterating over lists is a great place for catastrophic typos to occur. But more importantly, when I'm in the zone cranking on some code, writing an old-style loop breaks my mental stride much more than the new-style loop. Even if I happen to throw in a typo it'll be something the compiler will catch, whereas with the old-style I have to be more attentive to the syntax itself (instead of maintaining my focus on what the loop is accomplishing).
Everybody's Doin' It.
The last reason I moved to Objective C 2.0 is momentum. Most new projects and new developers (of which the iPhone has brought many) are using ObjC 2.0, are writing example snippets with ObjC 2.0, and are happy with ObjC 2.0. There are some ideological wars I think are worth fighting, but fighting to keep a programming language more open on a completely closed platform just doesn't feel like one of them.
So in the end, I suppose it really didn't take much at all to get me to jump off my high horse. It was probably a bit silly of me to climb on in the first place. Is anyone else still fighting the good 1.0 fight, or did you have different reasons for deciding to switch to 2.0?
I have the same complaint against the Python attributes. They are a neat way of simplifying syntax, but I think they violate the principle of least surprise in a major way. I want to--and do--use them, but I feel dirty afterwards. Like I had just killed a turkey with my bare hands only to be reminded that we actually needed a chicken instead. Damn it.
Ahem. While we're sidetracked, I've never been quite sure how the language famous for monkey-patching also championed the principle of least surprise. It'd be like Java heralding concise syntactic elegance. But ad hominem attacks aside, it's a damn fine principle, even if it often contradicts the principle of doing cool shit to make friends and influence Redditors.↩
"Wait you ignorant fool," says Angry Commenter, "You can use garbage collection. How do you even turn on your computer if you're so dense?" Well, I do mostly iPhone development, which doesn't support GC, so the garbage collection stuff doesn't do much for me in general, and had nothing to do with why I belatedly switched from ObjC 1.0 to 2.0.↩
I thought that you weren't supposed to use dot syntax when deallocing --- don't want KVO stuff to go off during dealloc or something?
Iterators are also more efficient then the standard loop. The compiler can often do a more efficient job with some tricks of optimizing the code.
Come on, who writes like this:
when you can write:
? :)
People who care about their high-water mark?
I think a lot of people would write the first, because it is a universal construct whose syntax is identical across the majority of popular programming languages (Java, ObjC, Perl, JavaScript, etc). For people who use ObjC but use a number of other languages, it is easier to reuse what they know. Not better, mind you, but easier.
But it's faster! :) "foreach" syntax is even faster, though.
OMG!
I'm unsubscribing from my mind.
in your example you define a *int and later refer to it as an int.
are you supposed to only use properties with pointers or can you use them with static vars?
You're right to be confused, it should have been
intnot* int. A typo.wow, pointer to an int in your class ... nice one.
i just removed your blog from my feed reader.
Yep. I removed it from my feed reader a few weeks ago too.
A bit more seriously, do you actually stop and think about passing by value versus passing by reference when you write code? I can't imagine anyone who would treat pointers with such reverence for more than a week or two as they first deal with a language that makes the distinction clear.
If I had consistently referenced ints as pointers, instead of just once, I would agree that it it would be terrifying to read my advice and writings. Instead, something like value/reference isn't something that I even think about when coding, I just do it. The same goes for other basic conceptual level task like picking between map/reduce/for/while or whether to use a simple C array or an NSArray.
If you're making a conscious-level decision whether or not to use a pointer, then you're either new to the pointer concept, or doing something wrong. Viewing a misplaced pointer as something more dire than a typo in for-loop syntax is buying into the pointers are hard mindset, and I just don't buy it.
so why haven't you corrected it (the typo) by now?
Reply to this entry