한줄요약
PWT는 프로토콜을 사용할 때 이 프로토콜이 어떤 주소를 바라봐야 하는지를 적어놓은 주소록이다. 이는 다형성 때문에 컴파일러 입장에서는 어떤 것이 올지 알 수 없다. 이에 컴파일러에게 PWT는 명확한 주소록을 제공해준다.
방금 위에서 말해준 sil_witness_table 의 정체, PWT에 대해 공부해보아요.
Swift에서 함수를 실행할 때, “어느 코드를 실행할지” 결정하는 방식은 두 가지에요.
문제는 프로토콜이에요.
protocol Speaker { func speak() }
struct Dog: Speaker { func speak() { print("Woof") } }
func makeItSpeak(heros: Speaker) {
heros.speak() // 여기서 dog의 speak를 부를지, 다른 동물의 speak를 부를지 어떻게 알까?
}
Speaker 라는 프로토콜 타입은 크기도 제각각인 여러 타입(Dog, Cat 등)을 담을 수 있어야 해요. 이때 사용하는 것이 Existential Container 와 PWT 에요.
PWT는 특정 타입이 특정 프로토콜을 어떻게 구현했는지 기록한 “함수 주소록” 이에요.
동작 과정
makeItSpeak(heros: Speaker) 가 호출되면, Swift는 heros 가 담긴 컨테이너에서 PWT를 찾아요.speak() 함수가 실제 Dog의 것인지 Cat의 것인지에 대한 메모리 주소가 적혀있어요.아까 봤던 SIL 코드의 마지막 기억 나세요?
sil_witness_table ViewType: Hashable module ViewType {
base_protocol Equatable: ViewType: Equatable module ViewType
method #Hashable.hashValue!getter: <Self where Self : Hashable> (Self) -> () -> Int : @$s8ViewTypeAAOSHAASH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance ViewType
method #Hashable.hash: <Self where Self : Hashable> (Self) -> (inout Hasher) -> () : @$s8ViewTypeAAOSHAASH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) in conformance ViewType
method #Hashable._rawHashValue: <Self where Self : Hashable> (Self) -> (Int) -> Int : @$s8ViewTypeAAOSHAASH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) in conformance ViewType
}
sil_witness_table ViewType: Equatable 이 바로 “ViewType이 Equatable로서 행동할 때 사용할 주소록은 이거야!” 라고 선언해 둔 것이에요.