Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is casting a struct to AnyObject not a compile error in swift?

Tags:

casting

swift

The code below compiles and works in swift.

struct TestStruct {
    let value: String = "asdf"
}

func iWantAReferenceType(object: AnyObject) {
    print(String(describing: object))
}

let o: TestStruct = TestStruct()

iWantAReferenceType(object: o as AnyObject)

I expected this to be a compile error because a struct can never conform to AnyObject. As demonstrated below by code that fails to compile.

protocol Test: AnyObject {

}

//Compile error: because a struct cannot be AnyObject
struct TestStruct: Test {
    let value: String = "asdf"
}

I am aware there is some bridging that can happen for certain types such as String. This would convert the value type of a reference type.

print(Mirror(reflecting: "asdf").subjectType) //print: String
print(Mirror(reflecting: "asdf" as AnyObject).subjectType) //print: NSTaggedPointerString

In writing this question I thought to see what the type of the cast object was and it seems it is also bridged in someway.

print(Mirror(reflecting: o).subjectType) //prints: TestStruct
print(Mirror(reflecting: o as AnyObject).subjectType) //prints: _SwiftValue

Why is this type of casting allowed? It seems to be breaking the contract for the function that is expecting a reference type.

I stumbled on this by accident when refactoring some code to support value types, to my surprise it had already been working for value types even though I thought it wouldn't. Is it safe to rely on this behaviour?

like image 609
nacross Avatar asked Jan 27 '19 02:01

nacross


1 Answers

This is a feature to facilitate passing to Cocoa. Any struct can be wrapped into a SwiftValue reference type. If you print type(of: object) you'll see the wrapper.

I don't think there is any contract for "expecting a reference type." More importantly, while "value types" and "reference types" exist in Swift, what really matter is value and reference semantics, which are not expressible in the language. You can create value semantics in reference types and reference semantics in value types, so the Swift type system really isn't of any help in that regard.

The important point here is that you only get this unusual behavior if you explicitly request it by asking for as AnyObject. There are very few reason to write that, and if you are, you had better know exactly what you're doing.

like image 106
Rob Napier Avatar answered Oct 07 '22 07:10

Rob Napier