Is autorelease no longer in pure swift arc?

I've looked at some disassembly of compiled swift code, and I surprised that there is no autorelease calls.

In objc, compiler insert autorelease calls when some method returns reference counted objects, if that method is not marked with ns_returns_retained attribute. As far as I know, it is done so to eliminate multiple release calls in chained property access, for example:

id d = a.b.c;
do(d);
return;
// Compiler generates (pseudocode):
$temp1 = a.b;
$temp2 = $temp1.c;
objc_retain($temp2); // only last member in chain needs to be retained and released
do($temp2);
objc_release($temp2);
return;

But in swift I see behaviour like in objc where every method marked with ns_returns_retained:

let d = a.b.c
do(d)
return
// Compiler generates (pseudocode):
$temp1 = a.b
$temp2 = $temp1.c
do($temp2)
swift_release($temp1) // every member in chain needs to be released
swift_release($temp2)
return

I know that objc behaviour produces less code only for long chains (3 and more, I guess?), that are rarely seen in code, and, also, there is no need for swift arc to be compatible with MRR ObjC code. Probably those facts were considered when implementing swift arc.
If that the case, this is great news, but I didn't find any mention in the web about that glorious elimination of autorelease, autorelease pools and all unpredictability associated with it :)

1 Like

Native Swift code won't ever use autorelease, and the default calling convention indeed is like ns_returns_retained. Unlike ObjC, callers are also responsible for guaranteeing the lifetime of all arguments, so arguments do not need to be defensively retained either. However, if Swift calls into Objective-C code, or Objective-C calls into @objc Swift methods, then Swift will still retain compatibility with the Objective-C conventions, including autoreleasing return values.

5 Likes

Does that sounds like now we have guarantee that whatever we do in called function scope, objects that are allocated there will never outlive the function call? (not considering storing them in some global things, of course). And this code would implement actual RAII?

func foo() {
  withExtendedLifetime(Resource()) {
    /* code */
  }
}

You should still use withExtendedLifetime if you need to guarantee the lifetime of a resource up to a certain point. Functions can still be inlined, and the optimizer may choose to shorten the lifetime of objects if they aren't used. The optimizer in general won't extend the lifetimes of things, though, and if you never interact with ObjC code then objects won't be implicitly autoreleased.

1 Like

That’s awesome, thanks for clarification!

1 Like