2

How is it possible to pass around a protocol instance if the implementing type is a ValueType? When you pass around a protocol you have no knowledge of the underlying type. It could be ValueType or it could be ReferenceType.

I have a struct MyStruct that implements some protocol VectorProtocol. I then have a function called arrayMaker that basically is just going to create instances of MyStruct and return one of those. This function is a bit convoluted for the example, I admit.

ArrayMaker is returning a protocol, but the implementing class is a ValueType. How exactly is the lifetime of this object now managed given this is concretely a ValueType? I could even take this protocol instance and store it for a very long time as a member to some other class.

Basically: I'm not sure how it is that the instance I return from this function can continue to live without reference semantics.

Is it possible for a struct to somehow be quietly promoted to reference semantics by Swift?

import Foundation

protocol VectorProtocol {
    var x: Int { get set }
    var y: Int { get set }
    var z: Int { get set }
}

struct MyStruct : VectorProtocol {
    var x: Int;
    var y: Int;
    var z: Int;
}

func arrayMaker() -> VectorProtocol {
    // protocolArray, and everything in it should be released
    // from memory upon function exit I would think
    var protocolArray: [MyStruct] = []
    for _ in 1...5 {
        protocolArray.append(MyStruct(x: Int.random(in: 0..<10), y: Int.random(in: 0..<10), z: Int.random(in: 0..<10)))
    }
    // only makes sense to me for this to live if semantics are reference
    return protocolArray[3]
}

let vectorProtocol = arrayMaker()

print("Protocol has X Value: \(vectorProtocol.x)")
jub0bs
  • 60,866
  • 25
  • 183
  • 186
Pali
  • 77
  • 7
  • 3
    I'm not entirely sure what you're asking. If a variable has value-type semantic, like `MyStruct`, then when assigning to another variable, a copy is assigned. If the variable is a reference-type (`MyClass`), a reference is assigned. Regardless, arrays behave like value-type (with copy-on-write optimization) – New Dev Jul 06 '21 at 18:48
  • 1
    You might find this interesting: https://stackoverflow.com/a/68024022/3141234 – Alexander Jul 06 '21 at 19:31
  • "everything in it should be released from memory upon function exit I would think". Nope. The array itself is a stack-allocated (kind of, it's complicated.) struct that's returned (by copy). The array's storage is a heap-allocated buffer that isn't released on return of the function. – Alexander Jul 06 '21 at 19:32
  • I understand the array is managing a heap allocated buffer, but the array was declared in the local scope of the function with no copy or reference made to keep it alive afterwards. So upon exit it must all be cleaned up. Given Rob's answer, the entry I selected will be copied into a box and that result will be returned. The array and all of its contents will be released. – Pali Jul 06 '21 at 19:40
  • That link was very useful though, thanks! – Pali Jul 06 '21 at 19:46

1 Answers1

4

The return value of VectorProtocol is a protocol existential, which is basically a 3 word "box" around a value. Your value is only 3 words long, so it will fit in the box. (If it were larger than 3 words, it would be copied into heap storage, and the box would memory manage it).

These 3-word boxes are passed on the stack, so they don't require any heap memory. The three values are just put directly on the stack (together with a few other words of housekeeping).

If this were a class, then the existential box would just hold a pointer to it (along with a few other words of housekeeping).

This was all explained in the WWDC 2016 session 416, Understanding Swift Performance, but Apple appears to have removed that from developer.apple.com. You can still find some notes about it at WWDC Notes and the transcript is available through the Wayback Machine.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610