[swift-users] Passing value types or members of value types?

Brent Royal-Gordon brent at architechies.com
Sun May 7 00:37:03 CDT 2017


> On May 6, 2017, at 9:33 PM, Kelvin Ma via swift-users <swift-users at swift.org> wrote:
> 
> If I have a “large” struct like
> 
> struct Vertex
> {
>     let x:Double, y:Double
>     var r:Int, g:Int, b:Int
>     let s:Double, t:Double
>     var selected:Bool
> }
> 
> and I want to pass it to a function without modifying it like
> 
> func taxicab_distance(_ v1:Vertex, _ v2:Vertex) -> Double
> {
>     return v2.x - v1.x + v2.y - v1.y
> }
> 
> Will the entire struct Vertex get copied and pushed onto the stack, or will only the relevant members be passed to the function?
> 
> In other words, does the compiler know to optimize this call down to
> 
> func taxicab_distance(v2x:Double, v1x:Double, v2y:Double, v1y:Double) -> Double
> {
>     return v2x - v1x + v2y - v1y
> }

When passed as an argument, a struct is recursively broken up into individual primitives, and each of those is passed in separate arguments. (The primitive types in question are mostly special "builtin" types which are wrapped by standard library types like `Int` and `Double`.) As far as I'm aware, there is no optimization that removes unused parts of the struct. That means this would be passed as something like:

func taxicab_distance(_ v1.x._value: Builtin.Float64, _ v1.y._value: Builtin.Float64, _ v1.r._value: Builtin.Int64, _ v1.g._value: Builtin.Int64, _ v1.b._value: Builtin.Int64, _ v1.s._value: Builtin.Float64, _ v1.t._value: Builtin.Float64, _ v1.selected._value: Builtin.Int1, _ v2.x._value: Builtin.Float64, _ v2.y._value: Builtin.Float64, _ v2.r._value: Builtin.Int64, _ v2.g._value: Builtin.Int64, _ v2.b._value: Builtin.Int64, _ v2.s._value: Builtin.Float64, _ v2.t._value: Builtin.Float64, _ v2.selected._value: Builtin.Int1) -> Builtin.Float64 { … }

Because of this, it may sometimes make sense to convert large structs into copy-on-write types by hand—basically, make a struct which wraps an inner class type, guarding all mutations with an `isUniquelyReferenced(_:)` check. (You're right that there's no implicit copy-on-write behavior in structs currently—when a struct has copy-on-write behavior, it has been manually implemented that way.)

Note that this may not always be the case: There's a built-in copy-on-write optimization which will soon come to instances which have been cast to a protocol type, and the "resilient" structs planned for a future version of Swift will probably be passed by reference in some way. But I believe that's the state of things in Swift 3.

-- 
Brent Royal-Gordon
Architechies

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170506/d6652a78/attachment.html>


More information about the swift-users mailing list