How to distinguish between value type and reference type?

How many ways can I distinguish between value types and reference types?

What is the type of closure ? Value type? Reference type ? How to prove it ?

Eg:


          struct ValueType {
               var age = 18
          }
    
          class ReferenceType {
                var age = 18
          }

       /// `Value Type`
        let valueType = ValueType()
        
        var valueType1 = valueType
        valueType1.age = 23
        
        print("""
                 valueType.age:\(valueType.age)
                 valueType1.age:\(valueType1.age)
              """)
       /// Prints       valueType.age:18
       ///                 valueType1.age:23
        
        /// `Reference Type`
        let referenceType = ReferenceType()
        
        let referenceType1 = referenceType
        referenceType1.age = 23
        
        print("""
                 referenceType.age:\(referenceType.age)
                 referenceType1.age:\(referenceType1.age)
              """)

        /// Prints       referenceType.age:23
       ///                  referenceType1.age:23
2 Likes
func isReferenceType(value: Any) -> Bool
{
  return type(of: value) is AnyClass
}
3 Likes

That's not correct for closures, which are reference types

print(isReferenceType(value: isReferenceType(value:))) // => false
2 Likes

How to prove that a closure is a reference type?

What is the essential difference between reference types and value types?

If you copy a value type, you get a second, identical, but distinct instance.
If you copy a reference type you get a reference to the same instance.

2 Likes

Keep in mind that the concept of reference semantics is different from the concept of reference types:

  • A value type can have reference semantics. For example, a file descriptor on Unix platforms is a CInt, but that definitely has reference semantics.

  • A reference type can have value semantics. The most common example of this is an immutable class.

You can’t use the type system to check for reference semantics.


The question of how to formalise value and reference semantics is super subtle and has been discussed many times here on DevForums, to the point where folks have published research papers on the topic.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

14 Likes

On copy, you get a new reference to the same underlying closure (with the same captured state). It's easy to see this by seeing what happens when you mutate the state:

func createCounter(initial: Int) -> () -> Int {
    var counter = initial
    return {
      counter += 1
      print("the new counter value is \(counter)")
      return counter
    }
}

let a = createCounter(initial: 0)
let b = a // new reference the same underlying counter
_ = a() // increment through the reference "a"
_ = b() // increment the same closure through reference "b"
2 Likes

Although I know closure is a reference type (I remember this is mentioned in the swift language book), I don't think this example is sufficient to prove it. It only proves that the captured variable (counter) has reference semantic. If closure was a value type, it would have the same output :slight_smile:

1 Like

@King-Eternal I think you'll find the Modern Swift API Design talk from WWDC 2019 quite interesting and informative on the subject of reference vs value semantics (and details how a value type that contains a reference value can take on reference semantics)

1 Like

My take on value vs reference topic, is that every type is a value type, but it varies per type what is included and what is excluded from the definition of value. In case of references to the mutable class, only object identity is part of the value.

2 Likes

Thanks.
I learned a lot from it Modern Swift API Design

1 Like