Existential any

권승용(Eric)·2024년 11월 15일

TIL

목록 보기
11/38

배경

  • 아무 생각 없이 프로토콜을 작성하다가... associatedtype을 사용한 프로토콜을 타입으로 사용할 땐 any를 붙여줘야 한다는 warning을 보게 되었다.
protocol SomeProtocol {
  associatedtype SomeType
  // ...
}

let someProperty: any SomeProtocol // <- any를 붙여주지 않으면 오류 발생
  • associatedtype을 사용하지 않은 프로토콜은 any를 붙여주지 않아도 아래와 같이 타입으로 선언 가능했다.
protocol SomeProtocol {
  // ...
}

let someProperty: SomeProtocol // <- any를 붙여주지 않아도 오류 없음

any는 어디서 나온 것인고?

  • 관련해서 찾아보던 중, 이는 Swift 5.6에서 제안된 키워드임을 알 수 있었다.
  • Swift Evolution 중 SE-0335 Proposal을 살펴보면 existential any 를 제안하며 프로토콜과 같은 existential 타입 앞에 any를 붙여야 하는 이유를 설명해주고 있다.

Existential 타입이 뭔데?

  • 프로토콜을 사용한 배열을 생각해보자.
  • 해당 배열에는 프로토콜을 준수하는 어떤 타입이던 들어갈 수 있다.
  • 그런데 배열은 각각의 요소가 차지하는 메모리 공간이 모두 똑같은데, 어떻게 서로 다른 크기의 타입 인스턴스들이 같은 배열에 들어갈 수 있는 것일까?
  • Swift는 Existential Container라는 특별한 저장 레이아웃을 사용해 이 문제를 해결한다.
  • 사실 배열에는 각각의 인스턴스가 아닌, Existential Container가 저장되고, 해당 Existential Container가 각각의 인스턴스 정보를 관리하고 있었던 것이다.
  • 프로토콜을 타입으로 사용할 경우, 이렇든 Existential Container에 의존하기 때문에 Existential type이라고 한다.
  • 따라서 Existential type은 프로토콜 타입을 뜻함!

any를 붙여야 하는 이유

  • Swift의 Existential 타입은 굉장히 가벼운 문법을 가지고 있다.
    • 다른 타입의 선언과 다를 바가 없음.
  • 그러나 그에 비해 Existential 타입이 가지는 임팩트는 크다.
    • 프로토콜 타입은 구체 타입 인스턴스가 아닌, Existential Container를 통해 각 인스턴스를 관리하게 된다.
    • 따라서 함수 호출이 동적으로 동작(dynamic dispatch)하게 되며, 이는 무겁게 동작한다.
    • 값 타입을 저장하더라도 3 word 크기를 넘어가면 Existential Container가 관리하는 별도의 공간에 저장된 후 Existential Container에 의해 관리된다.
    • 따라서 힙 할당 오버헤드도 발생~~!!
    • 그래서 꼭 필요한 경우가 아니라면 쓰지 않는 것이 좋음
  • 따라서 any를 붙여 이것이 Existential 타입임을 명시적으로 나타내어 혼란을 줄이자는 것이 주요 내용이다.
    • 아무 생각 없이 프로토콜 타입 쓰지 않게
    • any로 구분짓자!

Swift 6에서의 Existential any

  • Swift 6부터는 Existential type 에서의 any가 필수적이도록 변경된다고 한다.
  • 따라서 프로토콜 타입을 선언할 땐 any를 붙여줘야 함
  • 사용자의 실수를 방지하는 안정성 + 가독성 좋은 언어라는 지향점에 한발 더 가까이 다가간 것 같아서 기분좋음~
profile
ios 개발자에용

0개의 댓글