Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

For anyone curious as to what ARC is in this context (not the dialect of Lisp HN is written in): https://en.wikipedia.org/wiki/Automatic_Reference_Counting

Last time I did any Objective-C you had to retain/release yourself so the auto stuff is interesting. As far as I can tell the benefit over Garbage Collection is that GC only works well when you have lots of excess spare memory, which is constrained on mobile devices.



There are hybrid systems that combine the prompt deallocation of pure reference counting with the superior throughput of tracing garbage collection.

Part of the reason I really dislike the "reference counting vs. garbage collection" debate, and keep emphasizing that reference counting is garbage collection, is that it sets up this false dichotomy. In reality, there are all sorts of automatic memory management schemes that combine aspects of reference counting with tracing in different ways, most of which were created in the 80s and 90s. Sadly, almost nobody in industry is aware of this enormous body of work, and the simplistic "RC vs. GC" model has stuck in everyone's heads. :(


Not just is reference counting a form of garbage collection (as pcwalton pointed out), it is also not the case that you had to retain/release stuff yourself, certainly not since Objective-C 2.0's properties.

Here is the code to define and use a property pre ARC with properties:

   @property NSString *name;
   ...
   object.name = @"Marcel";
And here is the same code with ARC:

   @property NSString *name;
   ...
   object.name = @"Marcel";

Spot the difference? Now it turns out that there are some differences, such as automatic generation of -dealloc methods and weak references and some cosmetic stuff. But overall, it's at best a subtle difference and for most code you won't be able to tell the difference.

Pre Objective-C 2.0, there were solutions such as AccessorMacros[1], which handled the same use-cases except without the dot syntax (which is somewhat questionable) and have the advantage of being user-defined and user-extensible, so for example if you want a lazy accessor, you don't have to wait for your liege lord, er language supplier to add them, or create a whole new language to do the trick. Instead, you just write 4-5 lines of code and: done!

[1] https://github.com/mpw/MPWFoundation/blob/master/Classes/Acc...


This is one of the most uninformed posts I have read in a while. As someone who has been developing in Objective C for the last 6 years, and been through the transition of MRC to ARC, none of what is stated in this post is accurate.


Actually, all of it is accurate. Since you're spouting off your credentials as the only evidence for why what I wrote is wrong [not sure how that works], here are mine:

- programmed in Objective-C for ~30 years

- implemented my own pre-processor and runtime (pre NeXT)

- programmed in the NeXT ecosystem professionally since 1991

- additionally, worked in Objective-C outside the NeXT/Apple ecosystem for many years

- worked with Rhapsody and with OS X since the early betas

- worked at Apple for 2 years, in performance engineering (focus: Cocoa)

- one of my projects was evaluating the GC

With that out of the way (and just like your 6 years, it has no actual bearing on correctness): which specific parts do you believe are inaccurate? I'd be happy to discuss, show you why you're wrong, or correct my post if you turn out to be right on something that can be verified (your opinion as to how awesome ARC is doesn't count).


I'm guessing LeoNatan has an issue with:

> it's at best a subtle difference and for most code you won't be able to tell the difference.

Which is a pretty dubious claim. I removed a lot of retain/release/autorelease calls when I moved to ARC. Perhaps I'm missing the OP's point...


Can you quantify "a lot"?

My personal frameworks consist of 205584 non-comment, non-whitespace, non-single-bracket lines of code. Of these, 304 contain a retain, 1088 an autorelease, and 957 a release. That's 0.15%, 0.52% and 0.46% of the code respectively, for a grand total of 1.13%.

I'd have a hard time calling around 1% of total code "a lot", especially since the bulk of that is very simple boilerplate and trivial to write, but I guess everyone is different.

Mind you, this is a less-than-optimal code base, dating back to the mid 1990ies, with much more "but I am special" code that does do manual management where it shouldn't. Code I write today, even without ARC, has a significantly lower R/R density, well under 1%.

However, even of that 1%, the bulk is (a) releases in dealloc and (b) autorelease in class-side convenience initializers.

Quite frankly, I really miss convenience initializers in typical ARC code, writing [MPWByteStream streamWithTarget:Stdout] is so much nicer than [[MPWByteStream alloc] initWithTarget:Stdout] that (a) I wish people would write convenience initializers even in ARC mode (my experience is that they don't) and (b) I wrote a little macro that will generate an initializer and its convenience initializer from one specification. It's a bit nasty, so not sure I'll keep with it.

For the releases in dealloc, I once wrote an auto-dealloc that grubbed through the runtime to automatically release all the object instance variables (with an exception list for non-retained ones). It probably would have allowed me to eliminate the bulk of releases, but somehow I just didn't find it all that advantageous, writing those dealloc methods was just not that much of a hassle.

What may be interesting here is that the fact that I had an alternative may have been instrumental to realising it wasn't that big a deal. Things seem a lot worse when you don't have an alternative (or feel you don't have an alternative).

The same applies to ARC itself, at least for me: before ARC was released, it was exactly the solution I had wanted, especially in light of the GC madness. Again it was once I had used it in practice that it really became obvious how insignificant of an issue R/R was.

The only way I can see of getting significantly higher than 1% R/R code is by accessing instance variables directly, either because you are writing accessors by hand (why?) or grabbing at those instance variables without going through their respective accessors (why?!?!?). In both cases: don't do that.

Yet, whenever I mention these straightforward facts (particularly the numbers), people jump at me. Which is interesting in and of itself. My only explanation so far is that people generally write much, much worse code than I can imagine, or that R/R looms much larger in the collective Apple-dev psyche than can be justified by the cold, hard facts of the matter.

My guess is that's it's a little of the former and a lot of the latter. As a case in point, one dev who had jumped at me on a mailing list came back to me a little later in a private mail. He had converted one of his ARC projects back to R/R and was surprised to find what I had written to be 100% true: the R/R portion of the code was tiny and trivial, much less than he'd imagined, and hardly worth noticing, never mind fretting about.

However, the collective paranoia around R/R and the RDF around ARC seems to be big enough that reality doesn't really stand a chance. Which is of course also relevant. Perception matters, and that's why ARC is important.




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

Search: