cleanUrl: /programming/opaque-return-type

Generic Protocol의 한계

저번 포스트에서 Generic Protocol의 용도와 한계에 대해서 다뤘습니다. 간단히 복습해 보자면 다음과 같이 정리 할 수 있겠습니다.

코드로 보면 아래와 같습니다.

protocol Identifiable {
    associatedtype ID_TYPE: Equtable
    var id: ID_TYPE { get set }
    init()
}

class Student: Identifiable {
    var id: Int
    required init() {
        id = 0
    }
}

class AppleDevice: Identifiable {
    var id:String
    required init() {
        id = "asdf-1234"
    }
}

func getSomeIdentifiable() -> Identifiable {
    return AppleDevice() // Compile Error!!
}

이 때 컴파일 에러의 내용은 다음과 같았습니다.

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

기존의 에러 대처 방법

Generic Protocol은 “Generic Constraint”로만 사용될 수 있다고 합니다. 이게 무슨 말일까요? 말로 설명하는 것 보다, 아래 코드로 보여 드리는 편이 이해가 쉬울 것 같습니다.

func getSomeIdentifiable<T:Identifiable>() -> T {
    return T() // Identifiable이 T에 대한 제약(Constraint)로 사용되고 있습니다.
}

var iPhone:AppleDevice = getSomeIdentifiable()
print(iPhone.id) // id타입은 String
var bob:Student = getSomeIdentifiable()
print(bob.id) // id타입은 Int

이렇게

컴파일러는 어렵지 않게 iPhone의 id 타입을 추론할 수 있고, 불평 없이 컴파일을 할 수 있게 됩니다.

기존 방법의 문제점

자, 그러면 아래와 같은 상황은 어떨까요?

var someIdentifiable = getSomeIdentifiable()
// id타입을 추론 할 수가 없습니다 ㅠㅠㅠ

어떤 Identifiable을 원하는지를 사용하는 측에서 명시해 주질 않으니까, 당연히 컴파일러는 불만을 표시 할 수밖에 없습니다. 그러면 이렇게 생각 할 수도 있습니다. “그러면 언제나 사용하는 측에서 Identifiable의 타입을 명시해 주면 되는 거 아냐?