Embrace Swift type inference
스위프트는 코드의 안전성을 훼손하지 않고 간결한 코드를 작성하기 위해 타입 추론(Type inference)을 광범위하게 사용한다.
이 영상을 통해 우리는 다음의 것들을 살펴볼 것이다.
- 타입 추론을 활용하는 법
- 컴파일러에서 타입 추론이 어떻게 동작하는지
- 타입 추론에 의해 발생할 수 있는 에러의 원인과 이를 해결하는 방법
What is type inference?
먼저 타입 추론이 무엇인지 간단하게 알아보자.
타입 추론은 프로퍼티에 타입을 명시적으로 선언하지 않아도 컴파일러가 문맥에 따라 타입을 추론하는 것을 말한다.
위의 코드에서 String
을 명시적으로 선언하지 않아도 컴파일러는 이를 String
으로 추론한다. 좀 더 복잡한 예제 코드로 타입 추론을 활용하고, 컴파일러에서 타입 추론이 어떻게 동작하는지를 살펴보자.
위의 코드에서 FilteredList
는 주어진 데이터를 리스트 형태로 보여주고 필터링 기능을 제공하는 재사용 가능한 뷰다. 이 FilteredList
는 재사용 가능해야 하므로 기본적으로 생성자 인자들은 제네릭 해야 한다. 위의 코드에서 FilteredList
를 사용하면서 따로 타입을 명시해 주지 않고 있다. 이는 컴파일러가 타입 추론을 하기 때문에 가능한 일인데, 이를 좀 더 알아보기 위해 FilteredList
가 어떻게 정의되어 있는지 코드로 살펴보도록 하자
Element
, FilterKey
그리고 RowContent
는 FileteredList
가 생성될 때 실제 타입, 즉 Concrete 타입으로 대체된다. 이제 선언부와 호출부를 나란히 두고 비교해보자.
제네릭 타입으로 인해 복잡한 선언부와 비교했을 때 호출부는 훨씬 깔끔한 코드임을 확인할 수 있다. 이는 컴파일러가 주어진 값들로 타입 추론을 하기 때문에 가능한 일인데, 타입 추론이 아닌 명시적으로 타입을 명시한다면 아래와 보다 복잡한 코드를 작성해야 한다.
그렇다면 컴파일러는 어떻게 타입 추론을 하는 것일까? 타입 추론은 일종의 퍼즐이라고 할 수 있다. 우린 퍼즐을 하면서 하나의 조각이 맞춰질 때 다음 조각을 자연스럽게 유추할 수 있다. 하나의 퍼즐이 맞춰질 때마다 다음 조각에 대한 단서를 우린 유추할 수 있다. 컴파일러는 이렇게 퍼즐을 풀 듯이 우리의 코드에서 단서를 찾아 퍼즐을 하나씩 맞춰가며 타입을 추론한다.
위의 코드를 사용해서 컴파일러가 어떻게 퍼즐을 맞춰가는지 살펴보자.
먼저 첫 번째로 인자로 넘기는 smoothies
라는 단서를 통해 Element
의 타입을 추론할 수 있다. smoothies
는 [Smoothie]
타입으로 Element
는 Smoothie
타입으로 대체된다.
우린 Element
라는 퍼즐 조각을 맞췄기 때문에 이를 통해 또 다른 단서를 얻을 수 있다. 바로 FilterKey
다. \.title
은 \Smoothe.title
로 대체되고 Smoothie
의 title
프로퍼티는 String
이란 것을 알 수 있기 때문에 FilterKey
는 String
으로 대체된다.
RowContent
역시 ViewBuilder
클로저 안에서 SmoothieRowView
가 반환되기 때문에 SmoothieRowView
로 대체될 수 있다.
이런 식으로 컴파일러는 이전 단계의 단서를 통해 하나씩 타입을 추론해 나간다. 하지만 이렇게 얻은 이전 단계의 퍼즐 조각(단서)이 맞지 않는다면 소스 코드에 에러가 발생했다는 것을 의미한다. 즉 맞지 않은 타입이 들어갔기 때문에 컴파일러는 더 이상 타입 추론을 진행할 수 없다.
Smoothie.title
이 아닌 Bool
타입의 Smoothie.isPopular
로 바꿔보자
그렇다면 컴파일러는 Bool
타입을 FilterKey
의 조각으로 사용할 것이다. 하지만 Bool
타입은 hasSubString(_:)
메서드가 없기 때문에 이후의 타입 추론을 진행할 수 없고, 에러를 뱉는다.
이렇게 스위프트 컴파일러는 추후에 에러 메시지를 출력할 때 사용하기 위해 에러 추적 기능을 타입 추론에 통합시켰다. 컴파일러는 타입 추론을 진행하면서 직면한 에러를 기록한다. 그리고 컴파일러는 에러를 고치고 타입 추론을 계속 진행하기 위해 휴리스틱을 사용한다.
그리고 타입 추론이 끝나면 컴파일러는 타입 추론을 진행하면서 수집한 에러를 actionable한 에러 메시지(자동으로 코드를 수정할 수 있는)나 에러를 발생시킨 실제 타입에 대한 메시지와 함께 개발자에게 알린다.
이렇게 통합된 에러 추적 시스템은 Xcode11.4의 스위프트 5.2에선 많은 오류 메시지에 도입되었고, Xcode12의 스위프트 5.3에선 모든 에러 메시지에 적용되었다. Embrace Swift type inference