
불투명 타입(Opaque Type)으로 내부의 구체 타입은 컴파일러가 알고 있으나, 외부에는 숨기는 프로토콜

protocol Shape {
func area() -> Double
}
struct Circle: Shape {
let radius: Double
func area() -> Double {
return .pi * radius * radius
}
}
struct Square: Shape {
let side: Double
func area() -> Double {
return side * side
}
}
// some을 이용해 반환 타입을 숨기고 정적 디스패치를 보장
func makeCircle(_ radius: Double) -> some Shape {
return Circle(radius: radius)
}
func makeSquare(_ side: Double) -> some Shape {
return Square(side: side)
}
호출자에게는 Shape 프로토콜만을 보여 구현을 숨길 수 있음.
각각의 makeCircle, makeSquare 메서드는 컴파일 단계에 구현 타입이 고정됨.
컴파일 단계에서 구현 타입이 고정되기에 속도와 최적화 면에서 유리
컴파일러는 이미 Circle 타입인 걸 알고 있으며, 코드 작성자 입장에서는 Shape로 추상화되어 작성 가능
protocol ImageFetching {
associatedtype ImageType
func fetch() -> ImageType
}
func makeFetcher() -> some ImageFetching {
RemoteFetcher() // RemoteFetcher: ImageFetching 구현체
}
associatedtype을 포함한 프로토콜 반환 시, some Protocol을 사용하여 연관 타입 정보는 유지되면서 내부 타입은 숨김// 제네릭 버전: T 타입에 제약을 걸어 함수 정의
func printElement<T: CustomStringConvertible>(_ element: T) {
print(element.description)
}
// opaque 타입 사용
func printElement(_ element: some CustomStringConvertible) {
print(element.description)
}
기존 제네릭 함수에 명시적으로 T 타입을 선언하던 부분을 프로토콜로 대체
기존에 함수 작성하던 것처럼 간단하게 구현 가능
func foo(flag: Bool) -> some Shape {
if flag {
return Circle()
} else {
return Rectangle() // ❌ 오류
}
}
https://velog.io/@js1436kt/Swift-Existential-Container
기존 컴파일러가 실제 구현될 타입을 모르기 때문에 런타임에 Existential-Container에 접근하는 일련의 과정으로 발생하는 오버헤드가 발생
some 키워드를 사용해 컴파일 타임에 구현될 타입을 알게 되고 정적 디스패치가 가능하게 하여 성능 향상 가능
실존 타입(Existential Type)으로 타입을 명시적으로 선언할 때 사용되며 일반 프로토콜 타입 사용을 명확하게 표현하는 프로토콜

any는 기존에 타입을 명시하던 것과 동일한 역할을 함.
ex)
func justFunc() -> Type {
...
}
func anyFunc() -> any Type {
...
}
둘 다 동일함.
any를 사용하면 existential(boxing)이라는 런타임 동작이 발생하며, 이는 포인터 간접 참조와 동적 디스패치를 수반
성능 관점에서 해당 부분이 문제가 될 수도 있다는 주의를 준다는 느낌.
existential(boxing)
any Protocol 타입은 실제 값을 existential container라는 박스로 감싸 저장
이 컨테이너는 최대 3개의 워드를 인라인으로 저장하지만, 이보다 큰 값은 힙에 할당
힙 할당과 해제 과정을 거치므로, 메모리 오버헤드와 ARC 레퍼런스 카운팅이 추가
https://github.com/hborla/swift-evolution/blob/existential-any/proposals/NNNN-existential-any.md
var delegate: Protocol
- 런타임에 타입이 바뀌는 애인가?
- 고정된 타입만 나오나?
var anyDelegate: any Protocol
- 런타임에 타입이 바뀌어요!!!!!!!!!!!
any를 활용해 명시적으로 런타임에 오버헤드가 있다는 것을 명시할 수 있게 됨.
기존에 혼동할 수 있던 부분을 명확히 잡아 줄 수 있음.
| 구분 | some Protocol | any Protocol |
|---|---|---|
| 타입 고정성 | 컴파일 시 단일 타입 고정 | 런타임에 여러 타입 허용 |
| 디스패치 방식 | 정적 디스패치 | 동적 디스패치 |
| 성능 | 빠르고 최적화 가능 | 약간의 오버헤드 존재 |
| 사용 위치 | 반환형, 파라미터, 프로퍼티 | 주로 파라미터, 프로퍼티, heterogeneous 컬렉션 |
| 유연성 | 구현은 숨기고 형식은 고정 | 다양한 타입을 자유롭게 담을 수 있음 |
참고
https://www.youtube.com/watch?v=0u4w6FaqhMs
https://www.avanderlee.com/swift/some-opaque-types
https://nsvasilev.medium.com/understanding-any-and-some-keywords-in-swift-462cb42cc913
https://forums.swift.org/t/relative-performance-of-existential-any/77299
https://www.donnywals.com/what-is-the-any-keyword-in-swift
https://github.com/hborla/swift-evolution/blob/existential-any/proposals/NNNN-existential-any.md
https://namitgupta.com/difference-between-some-and-any-with-protocols-in-swift