Currently the calling convention for non-trivial parameters in swift is that the caller transfers ownership to the callee.
In terms of reference counting, it means that arguments are passed with a +1 reference count.
This is good if the callee stores the argument or returns it, because a store/return needs a +1 reference count anyway.
class X { ... }
func caller() {
// retain x
foo(x)
}
func foo(x: X) {
arr[0] = x // no reference counting required
}
But in many cases, it ends up that the caller has to retain the argument and the callee just has to release the argument at the end of the function.
func foo(x: X) {
let y = x.value
// release x
}
Also, if an argument is used multiple times in the caller, it ends up being retained multiple times just to be released again in every callee.
func caller() {
// retain x
foo(x) // release x in callee
// retain x
bar(x) // release x in callee
// retain x
baz(x) // release x in callee
}
The argument convention has an effect on all arguments with non-trivial types, e.g. references, value types containing references or generic types.
The swift compiler has an optimization to change the convention for module-internal functions from "owned" to "guaranteed". "Guaranteed" means that the caller guarantees that the parameter is alive during the whole function call and the callee is not responsible for destroying/consuming the argument (also called: +0 convention). But the compiler optimization cannot change the convention for public API functions, because this would change the ABI.
We believe that the “guaranteed” convention would semantically fit better with most of library and framework APIs. In fact, this has been a longstanding request from some of the standard library contributors. Therefore we'd like to change the convention from passing parameters as "owned" to "guaranteed" by default.
Now there are certain kind of functions, which usually really "consume" their arguments: setters and initializers, because they usually store their arguments.
Those functions will stay with the owned-convention.
Note that this change is not a language change. Although it changes the lifetime of objects, the Swift language does not define when objects are being destroyed. So, except for performance and code size, this change should be transparent for users.
We are also planning to introduce new keywords (which still has to go through evolution) to manually change the convention for a specific parameter. For example this makes sense for functions which are conceptually a setter, like the argument of Array.append(). The standard library will use those keywords when appropriate. But of course, those keywords can also be used in user code.
Our preliminary measurements show that on average benchmark performance improves with the guaranteed convention (although there are also some regressions). Also code size improves on average (up to 5%). But this data is preliminary as we didn’t complete the implementation yet.
Feedback/comments are welcome.
Erik