Hacker News new | past | comments | ask | show | jobs | submit login
Objective-C literals for NSDictionary, NSArray, and NSNumber (cocoaheads.tumblr.com)
102 points by julien_p on Feb 19, 2012 | hide | past | web | favorite | 57 comments

Well, I guess that was long overdue. Anyway, another nice step to bring Objective-C forward.

It seems to develop into a nice combination of low-level, high-performance C and a pretty straightforward, dynamic, object system. In short, I vastly prefer its object system to C++, because it reasonably trades some performance for greater dynamisms and an easier syntax.

It'll be interesting how Objective-C will develop.

I completely agree, it's great to see that the language continues to move forward and advance in it's OO design. It's especially nice that these forward steps do not hinder or reduce Obj-C's low-level functionality, leaving available the performance gains from it's use.

Exactly, gcd could have been objc but it is just a c extension!!

This is for Apple LLVM 4.0 which ships with XCode 4.4.

Also included:

   - Automatic @synthesize
   - NSArray/NSDictionary subscripting, eg id object=MyArray[12];

For those wondering: Xcode 4.3 is what currently ships, 4.4 Developer Preview ships with the Mountain Lion per-release, so it only is available to those in Apple's Developer Program.

> ...so it only is available to those in Apple's Developer Program.

correction: Apple's Mac developer program. I'm an iOS developer and I don't see Xcode 4.4 in my dashboard.

This is the second time (to my knowledge, may have been going on for a while) that an Xcode beta has been made available to only one of the two (Mac and iOS) developer programs. The Xcode 4.3 beta was only available to iOS developers -- despite containing bug fixes and improvements useful to developers on both platforms. Now the Xcode 4.4 beta is only available to Mac developers.

I really don't see the logic in withholding from paying members of either platform.

You can't use the beta Xcode / SDKs to build apps for the relevant App Store anyway, so while it contains neat new features it's technically only useful for developers developing that particular pre-release OS (whether iOS 5.1 or OS X 10.8).

Interestingly now Xcode 4.3 is out of beta the iOS 5.1 SDK is still only available with Xcode 4.3 DP3 (although realistically there's not much public new stuff in iOS 5.1 since presumably it's all under wraps for the iPad 3).

Xcode 4.2 was also only available to iOS developers.

Xcode 4.1 was part of the Lion pre-release, so I don't think that iOS developers got it during beta, though apparently it was made available for SL users a few weeks after Lion shipped.

It at least makes sense to limit the betas to the Mac program only if the tool in question only works on a prerelease OS (I assume that's the case with 4.4 and ML). But limiting it to iOS developers only makes no technical sense at all.

Edit: 4.4 works on 10.7.3+, so yeah, this is just the usual bullshit.

That is correct. I installed Mountain Lion developer pre-release and Xcode 4.4 this week. BTW, I like Mountain Lion: I have it on my "work" laptop; seems solid.

This is fantastic. Previously I was employing a macro library that offered $dict(k, v, k, v) and $arr(1, 2, 3) and $bool. But the @[] feels much better, and it increases code portability if a class is not dependent upon a separate macro library. It will really remove the verbosity of objc which is oftentimes one of the major criticisms.

We've been talking about similar changes to Objective-J for quite some time (we already have JavaScript literals that map more cleanly than C ones). The one thing we've discussed that I don't think made it here is a set literal. It would be nice to have sets treated in a more first class way, considering how often arrays are used when sets would be more appropriate.

Indeed. Even [NSDictionary allKeys] returns an array instead of a set.

The excessively verbose collection syntax is my #1 pain point with Obj-C. Looking forward to kicking the tires on this one.

It's never before fully struck me how cleanly the "Objective-C is too verbose" complaint really breaks down to two separate issues: one of them being that method names are long (which is arguably a plus) and the other being mostly comprised of the stuff that's apparently mostly taken care of with this release. Actually, I suppose there used to be a third, too: (auto)release/retain statements all over the place.

As somebody who loves the long method names but of course wants less syntactic cruft, I'm really happy with their recent progress.

ARC in XCode 4.2 takes care of the release/retain business!

Kind of. It does not apply to all Cocoa libraries and you need to follow certain conventions, otherwise the compiler will fail to add the release/retain calls.

@-prefixed literals for collections are definitely welcome (I won't miss those nested 'dictionaryWith...' calls for sure).

Anyone know how the []-access will work? Is this going to be a special case for NSArray/NSDictionary synthesized in by the compiler, or is there going to be runtime support for a []-operator message a la Ruby, or maybe something related to key-value coding?

I hope this is done coherently, anyway. I worry that too many special cases to overcome problems like verbose collection access could snowball.

There are methods you can implement in your own classes to provide setting and getting for both the array and dictionary style syntax.

If you're a Mac developer, check the forums. Else, wait for the info to be non-NDA.

ugh. As much as I love the changes that Apple have been making to Objective-C, as someone with a rather large - first-time project undrway, the pace of change is just killing me. In the last three years we have seen blocks (and Grand Central Dispatch) and garbag collection, Automatic Reference Counting, and now this.

These are all good changes (well, except for garbage collection, but hey, they kicked that out with ARC anyway), but it really is hard to stay up-to-date. Yeah, I know, woe is me, my tools supplier is constantly supplying better free tools, but it is daunting having to review each of this evolutions, and determine if it is worth the effort to integrate it into my project.

Maybe I'm misunderstanding, but how much effort are you talking about here? Skipping @synthesize on properties or using literal syntax where/when it makes sense wouldn't cause much additional cognitive load and you don't have to convert old code to use the new sugar.

It's not as simple as that when you're planning for the long term. Firstly you need to examine the changes and make sure that they aren't going to create any compatability problems, of the type "if you activate this option, then you can no longer link to libraries that don't use this option". Garbage collection in particular had a lot of those sorts of problems.

But even if you can convince yourself that it is just syntactic sugar, you have to have a long hard think about whether or not you are going to adopt the style. Adopting means going back and changing the code you have already written. Not adopting the style is not tenable in the long term - the new syntax is clearly superior to the old syntax, so there will be a lot of pressure to code the new way. This is particularly true when playing in Apple's backyard, as they have a habit of taking a nice new technology that is optional in one release, and then building on that optional feature for a next release.

For me, in this one particular case, I'll probably go with the new syntax, going back through modules that are already written and redoing them with the new syntax each time I have to touch one for a bug fix/feature.

I'm just getting frustrated because my project started about 18 months ago - I work on it nights and weekends, and I have to keep stopping work on the project and spending time adapting to new tools. The last 18 months or so have been particularly tumultuous. XCode 4 was a big change compared to its predecessors. I started using the garbage collector just to have it more or less replaced by ARC.

None of this is insurmountable, but as a one person, part-time shop with a fairly ambitious project, this is really starting to become painful for me, which is the point I was trying to get across, and I suspect that I'm not the only one to be feeling the pain. Perhaps I would feel better about deciding not to follow Apple on this one if I could be sure that that decision wouldn't mean me finding myself with a big code base on my hands that is unable to take advantage of the new hotness in the next version of Objective-C because I decided to skip this version's changes...

This particular change takes about fifteen minutes to fully understand. Adopting does not require changing any existing code. I can kind of see where you're coming from in general, but attaching the complaint to this feature makes no sense to me. This stuff is pretty much pure win and no effort.

I understand what you mean; but in this case, I think it's fairly easy to adopt new syntax in all of you code base. Just search for NSArray arrayWithObjects:, NSDictionary dictionaryWithObjects: and NSNumber numberWithChar: and replace them with new syntax. It wouldn't be this easy if it was a major change (like ARC).

Why should you rewrite working code?

> but it really is hard to stay up-to-date.

Well, you don't really _need_ to; this one is just syntactic sugar, and the others, while nice (or mostly; I'm unconvinced about ARC), are not necessary. I'd prefer to have the options.

ARC is not really 'needed' for anything, it's just a very nice way to prevent memory leaks and pruning lots of retain/release statements from your code.

I would not re-factor existing code without ARC if it was properly debugged for memory leaks and working perfectly, but for all new projects I have it enabled.

Sorry, I meant that I'm unconvinced ARC is nice, not that I'm unconvinced it's not necessary; it clearly isn't.

Nice! As somebody who's not a member of the Mac Developer Program but whose Twitter feed has been full of people gushing about how nice the new additions to Objective-C are, I'm glad to see what all the hubbub is about.

I'm glad to see these additions, but the syntax for an NSArray literal bugs me.

When I want an array literal in C, I'd write ...

  int foo[] = { 1, 2, 3, 4, 5};
... but in Objective-C, for an NSArray literal I'd write ...

  NSArray *bar = @[o1, o2, o3];
Why did they choose '[' over '{'? Oddly enough, NSDictionary uses '{'.

I feel like the syntax for an NSString literal is more natural (as a C developer).

  NSString *baz = @"look, an NSString literal";
  char szBaz[] = "look, a C string literal";

Because presumably (I don't have the new XCode to check) you can do things like:

    [someObject dictArg:@{ a:@"B" } arrayArg:@[1,2,34]];
So if they were both using "{" to set them off the parser doesn't know which one you mean until it hits the first ":" (and it can't guess from the type when the type is "id"). Now that's not impossible to write a parser that looks ahead to figure out what you mean, but it's much easier to parse if they have completely different syntax from the outset. And the "{" vs "[" distinction is very standard amongst the higher level languages, even if it isn't in straight C.

I think they chose the [] for arrays and {} for dictionaries as that is the style that seems to be most popular right now. Python for instance uses this.

When adding features to something, I tend to be a big fan of "when in Rome"[1]. If these were extensions to Python (or Ruby or JavaScript) then I would totally be for using '[' with arrays. As a C guy though, I would rather have seen them use '{' for NSArray and '[' for NSDictionary. Regardless, I'm glad to see this stuff added.

[1] http://en.wiktionary.org/wiki/when_in_Rome,_do_as_the_Romans...

It's already custom in objc to use {} for dicts and [] for arrays when printing them out, unless I'm misremembering. It also matches the use of those characters in JSON, so it seems natural to me.

And Perl. And Javascript. And Ruby. There's lots of precedent.

Could be in case they want to do literal NSValues later. Since {}-syntax is used in C for both array literals and struct literals, they needed to change one, and the picked the more common one. Otherwise is foo in:

id foo = @{ @2, @5 };

an NSArray containing two NSNumbers, or an NSValue containing a struct with two pointers (which happen to be NSNumber *s)?

I'd guess there were other edge cases they didn't want to deal with, so they didn't do literal NSValues for this release.

Or it could be that it's because []-style arrays are popular these days.

Or some of both; in picking which {} to change to @[], they reasoned that lots of people have experience with []-style arrays.

> Why did they choose '[' over '{'? Oddly enough, NSDictionary uses '{'.

Who knows, but it seems to mirror Python in that respect. Being a fan of Python I can only approve.

Completely agree. Looks natural to me as a python/javascript guy

Perhaps they choose @[ for arrays because it requires less lookahead than figuring out whether @{ is the start of a dictionary or an array.

Well this is good news. I have nothing to complain about here, it was even done with the obviously correct syntax following the principle of least surprise. Yay!

On one hand, it's nice, and it'll make coding in Obj-C nicer.

On the other hand, it strengthens the coupling between Objective-C the language the Cocoa the framework, and I'm not sure how I feel about that.

I do like it better than the property dot syntax though. (is a simple assignment to a struct member? is it an objc_msgSend of unknown complexity?)

Apple's weird in the way they couple things in different ways than the rest of the industry and against the conventional wisdom. Since essentially nobody has an investment in Objective-C-without-Cocoa or Cocoa-without-Objective-C, I don't see any problem with them evolving them together whichever way seems best to them.

Also, there's long precedent with @"…" syntax for embedding NSString literals and most of the changes are really just preprocessor/static analysis-driven syntactic sugar — sometimes extreme sugar, yes, but optional, highly-predictable, purely-syntactic-cleanup nonetheless. So if they ever decide "the future of Cocoa is Ruby!" or something like that, I'd think most of the sugar could be, to mix metaphors, transplanted.

On that note, though: I don't see Apple moving primarily away from Objective-C any sooner than I see .Net moving primarily away from C#. It's "the language" until something huge changes the landscape, in large part because they've been able to so substantially evolve it, just like Microsoft, who also controls the primary framework used with their language, has been able to do with C#.

This doesn't do much of anything to increase coupling to Cocoa.

It does represent yet another link between the language syntax and the Foundation framework (along with NSStrings, blocks, etc), but Foundation is effectively part of the language.

Are there any drawbacks/pitfalls involved in creating a compiler that translates these literals to some other data structure library (such as glib, for example)?

Nice. I wish for ability for function to return multiple values. Is it possible at all?

Probably not, but with the new dictionary literal syntax, returning a dictionary with a set of keys-values should be a breeze :)

You can use C99 struct literals:

    return (struct x){a,b};
Small structs may be passed in registers. http://stackoverflow.com/a/3355560/27009

IIRC passing Obj-C object pointers in C structs is disallowed or discouraged by ARC.

You have to explicitly bridge them in or out of ARC and indicate the ownership rules. Sometimes, for example when you're interfacing straight C code, you have no other option.

Does this come courtesy of a new version of the Objective-C language?

The definition of ObjC confuses me a bit. It's said to be a superset of C - but which C? C89? C99? GNU-C-Something?

Objective-C is a proper superset of C89, C99 and K&R C. You can specify it at compile time --std.

Obj-C is essentially a preprocessor on top of a C compiler. Whether that C compiler is C89, C99, or C++11 is up to you.

Obj-C also includes the Foundation classes that were originally introduced with the OpenStep SDK in 1994 (NSObject, NSString, NSNumber, NSArray, NSRunLoop, NSAutoreleasePool, etc.).

Is it possible to see this straight C translation? Using Clang for example. I'm sort of aware of the "objc_msgSend" business, but would like to see more.

Talking of OpenStep, after seeing some of those NeXT videos on HN the other day, I found a torrent of OpenStep 4.2 incl the dev tools. It's a VMware image and boots and runs just fine. Pretty nifty. Then I noticed OpenStep 5.0 redirects to Mac OS X on Wikipedia!

Quick example of calling a method that doesn't take any arguments and returns an object:

  id foo = [self bar];
is the same as:

  id foo = self.bar;
which is also the same as:

  id foo = [self performSelector:@selector(bar)];

  IMP barImp = [self methodForSelector:@selector(bar)];
  id foo = barImp(self, @selector(bar); [1]
and finally:

  id foo = ((id)(id, SEL)objc_msgSend)(self, @selector(bar)); [2, 3, 4]
1. Because we're calling the IMP, or implementation, directly, we don't need a cast (like we do below, with objc_msgSend).

2. Casting the function is optional, but, helps to prevent things like endian differences and your return value getting mangled when using the same code on PPC and Intel. Not too big of a deal anymore.

3. There are actually two other varieties of objc_msgSend, depending on your return type — specifically, floating point calls should use objc_msgSend_fpret and calls that return a struct should use objc_msgSend_stret.

4. I hope I got this cast right, I didn't try to compile it.

Those first two and following aren't equivalent, are they? Wouldn't they compile, respectively, to:

    objc_msgSend(self, @selector(bar));

    objc_msgSend(self, @selector(performSelector:), @selector(bar));


The first two are the same, with a different syntax, yes.

They would both become:

  objc_msgSend(self, @selector(bar));
However, your examples are basically explicitly passing a message (1 and 2), vs dynamically building a message to pass (3).

For the second to work, the objc_msgCall function would really be:

  objc_msgSend(self, @selector(performSelector:), @selector(bar));
(The first example is saying to self to call the selector (method) named 'bar'. The second example is telling self to call the method 'performSelector:' with an argument of 'bar'.)

The runtime may or may not be smart enough to optimize this out. It has never been a bottleneck for me to bother looking into it, and I haven't come across anything to indicate one way or the other.

Check out clang's -rewrite-objc option. It outputs C++, not C, and isn't entirely truthful since Obective-C is compiled directly these days, but should give you what you're after.

Registration is open for Startup School 2019. Classes start July 22nd.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact