Swift Regret: inout Syntax
Swift regret: inout syntax
— Jordan Rose (@UINT_MIN) December 28, 2021
Swift has a notion of inout parameters, which are formally copy-in/copy-out (or perhaps move-in/move-out), and optimized to by-ref when possible. This is written `inout Foo` in the parameter type…and `&foo` at the call site.
Part of the Swift Regrets series.
Swift has a notion of inout parameters, which are formally copy-in/copy-out (or perhaps move-in/move-out), and optimized to by-reference when possible. This is written inout Foo
in the parameter type…and &foo
at the call site. Everyone would guess that this &
is in imitation of how you pass things by reference in C, by taking the address, and everyone would be right. But it’s not the same operation in Swift, and Quinn (@justkwin) has a post explaining how and why.
To make things more confusing but also necessarily practical, Swift does guarantee that if you use &
with a global or static property that’s stored without observers (willSet
/didSet
), then you will get a consistent pointer value every time. (Though Jens Ayton points out that it also has to be a non-zero-sized type.) Fun fact: this wasn’t really about proper pointers at all, but rather APIs that use an opaque void *
as a unique ID, including the non-block-based Key-Value Observing APIs. It was a common idiom to use the address of a private static, and we didn’t have an obvious replacement.
I forget if we extended the “stable address” guarantee to class instance stored properties as well. The “The Swift Programming Language” book doesn’t say anything about either exception (that I saw), but I’m confident in the global/static one.
Anyway, if you read Quinn’s article you’d know that the analogy with C is more trouble than it’s worth. So what would I choose instead? inout foo
, just like the declaration. We had considered this but figured it would be too noisy…but I think we didn’t account for most inout
happening implicitly through mutating
, which isn’t confusable for an address and doesn’t require any annotation at the call site. (Getting away from Cocoa’s out-param-based error handling in Swift 3 helped too.)