Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

sanichdaniel의 iOS 개발 블로그

Type Erasure 본문

swift

Type Erasure

sanich8355 2020. 9. 28. 18:00

요약

프로토콜을 제너릭하게 쓰고 싶으면 associatedtype을 사용하면 된다.
associatedtype은 프로토콜이 채택한 순간에 구체 타입으로 교체된다.
하지만 프로토콜을 채택하지 않고 그냥 함수의 인자, 리턴타입, 변수의 타입, 콜렉션의 타입으로 쓰는 경우 컴파일타임에 associatedtype의 구체 타입이 결정이 안되어 컴파일 에러가 난다.
이런경우에는 type-erasure wrapper-class를 만들어서 해결할수 있다.
애플 디벨로퍼 문서를 읽다가 Type-Erasing Wrappers를 발견했다.
무엇인지 알아보기 위해 공부해보았다.

Protocols & Associated Types

type-erasure에 앞서 protocol과 associated type에 대해 알아야한다.

associated type은 프로토콜과 제너릭(associatedtype)의 결합이다.

아래 예시에서 CarFactoryProtocol을 채택한다면 여러 타입의 차를 찍어낼수 있다.

protocol CarFactoryProtocol {
    associatedtype CarType
    func produce() -> CarType
}
struct ElectricCar {
    let brand: String
}
struct PetrolCar {
    let brand: String
}

struct TeslaFactory: CarFactoryProtocol {
    typealias CarType = ElectricCar
    
	func produce() -> TeslaFactory.CarType {
        print("producing tesla electric car ...")
        return ElectricCar(brand: "Tesla")
    }
}

struct BMWFactory: CarFactoryProtocol {
    typealias CarType = ElectricCar
    
	func produce() -> BMWFactory.CarType {
        print("producing bmw electric car ...")
        return ElectricCar(brand: "BMW")
    }
}

자 이제 여러타입의 전기자동차를 생산하는 팩토리들의 어레이를 만들고 싶다

또는 팩토리를 인자로 받는 함수를 만들고 싶다.

let KiaFactory: CarFactoryProtocol

/// or

let electricCarFactories: [CarFactoryProtocol]

/// or

func getCarFactory(factory: CarFactoryProtocol) { }

하지만 아래와 같은 에러가 발생한다

Protocol 'CarFactoryProtocol' can only be used as a generic constraint because it has Self or associated type requirements

원인 

Generic Type Parameters

placeholder 타입으로, struct, class, enum에서 사용된다.

컴파일 타임에 placeholder은 구현 타입으로 교체된다.

 

Associated Type

protocol에서 사용되는 placeholder이다. 

하지만 기존의 generic type parameter와 가장 큰 차이점으로는 placeholder가 교체되는 시점이다. 

구현 타입이 프로토콜을 채택한 시점에 associatedtype의 구현 타입이 채워집니다.

프로토콜을 채택해야 associatedtype을 제공하니, 만약 프로토콜이 함수의 인자, 리턴 타입, 변수의 타입, 콜렉션의 타입으로 사용되는 경우, 컴파일러는 associatedtype(플레이스홀더)의 구체 타입을 알 수가 없다.

컴파일러는 컴파일타임에 항상 구체 타입을 알아야한다. 

Type erasure to the rescue

Wrapper 클래스가 필요하다

랩퍼 클래스는 Factory 프로토콜을 채택한 인스턴스만 인자로 받아들인다.

또한 그 Factory 프로토콜의 CarType은 AnyCarFactory 타입 패러미터의 CarType과 같아야한다. 

struct AnyCarFactory<CarType>: CarFactoryProtocol {
    private let _produce: () -> CarType
    
    init<Factory: CarFactoryProtocol>(_ carFactory: Factory) where Factory.CarType == CarType {
        _produce = carFactory.produce
    }
    
    func produce() -> CarType {
        return _produce()
    }
}

factories에는 TeslaFactory, BMWFactory 같은 타입정보가 지워져있기에 type-erasure이라한다. 

보통 통상적으로는 랩퍼클라쓰는 Any가 앞에 붙는다

let factories = [AnyCarFactory(TeslaFactory()), AnyCarFactory(BMWFactory())]
factories.map() { $0.produce() }
// Output:
// producing tesla electric car ...
// producing bmw electric car ...

한계

추가적으로 보일러 플레이트 코드를 작성해야한다. 

추가적으로 알아두면 좋은것

opaque type은 type identity를 간직하기에, assoicated type의 구체 타입을 추측할수 있다

type-erasure말고 opaque type으로 해결할수 없는지도 고민해보자 

출처

krakendev.io/blog/generic-protocols-and-their-shortcomings

 

Generic Protocols & Their Shortcomings — KrakenDev

Generic Protocols, man. They. Are. Hard. Easy to create, but difficult to work with. For simple scenarios, they play well for the most part but unfortunately, the more complexity you create whilst working with them, the more you start to realize how much

krakendev.io

academy.realm.io/posts/tryswift-gwendolyn-weston-type-erasure/

 

Keep Calm and Type Erase On

Just when you thought having unambiguous types was the one true way of Swift, it turns out that sometimes it is necessary to erase types. …

academy.realm.io

www.donnywals.com/understanding-opaque-return-types-in-swift-5-1/

 

 

Understanding opaque return types in Swift 5.1 – Donny Wals

Have you ever wondered what the `some` keyword is in SwiftUI? It’s an opaque return type. Learn everything about opaque return types and how to use them.

www.donnywals.com

www.bignerdranch.com/blog/breaking-down-type-erasure-in-swift/

 

Breaking Down Type Erasure in Swift - Digital product development agency | Big Nerd Ranch

Check out our blog post Breaking Down Type Erasure in Swift from Big Nerd Ranch. Learn more and read it now!

www.bignerdranch.com

swiftrocks.com/using-type-erasure-to-build-a-dependency-injector-in-swift

 

Using Type Erasure to Build a Dependency Injecting Routing Framework in Swift

With Swift being a very type-safe and namespaced language, you'll find that certain tasks are really hard to complete if at some point you can't determine the types that are being handled - mostly when generics are involved. Using an automatic dependen

swiftrocks.com

'swift' 카테고리의 다른 글

Opaque Types  (0) 2020.09.29
enum vs protocol as UseCase  (0) 2020.09.28
initializer  (0) 2020.09.26
Self Type  (0) 2020.09.05
type(of:)  (0) 2020.09.05