본문 바로가기
Kotlin

[Effective Kotlin] 4 - inferred 타입으로 리턴하지 말라

by 매운돌 2023. 2. 19.

타입 추론은 JVM 세계에서 가장 널리 알려진 Kotlin의 특징이지만, 사용할 때는 몇 가지 위험성이 있으니 조심해야 합니다.

우선 할당 때 inferred 타입은 정확하게 오른쪽에 있는 피연산자에 맞게 설정된다는 것을 기억해야 합니다.

절대로 슈퍼 클래스 또는 인터페이스로 설정되지 않습니다.

open class Animal
class Zebra: Animal()

fun main() {
	var animal = Zebra()
    animal = Animal() // 오류: Type mismatch
}

일반적인 경우에 위의 문제는 아래처럼 타입을 명시적으로 지정하여 해결 할 수 있기 때문에 크게 문제가 되지 않습니다.

open class Animal
class Zebra: Animal()

fun main() {
	var animal: Animal = Zebra()
    animal = Animal()
}

하지만 직접 라이브러리(또는 모듈)를 조작할 수 없는 경우에는 이러한 문제를 쉽게 해결할 수 없습니다. 그리고 이러한 경우에 inferred 타입을 노출하면 위험한 일이 발생할 수 있습니다.

 

아래에 다음과 같은 인터페이스가 있다고 가정해 봅니다.

interface CarFactory {
	fun produce(): Car
}

그리고 기본적으로 지정된 값을 아래 처럼 있다고 선언할 수 있습니다.

val DEFAULT_CAR: Car = Fiat126P()

그리고 DEFAULT_CAR가 명시적으로 Car이므로, 따로 필요 없다고 판단되어 아래와 같이 함수의 리턴 타입을 제거했다고 합시다.

interface CarFactory {
	fun produce() = DEFAULT_CAR
}

그런데 누군가 DEFAULT_CAR는 타입 추론에 의해 자동으로 타입이 지정될 것이므로, Car를 명시적으로 지정하지 않아도 된다고 생각하여 이를 제거할 수 있습니다.

val DEFAULT_CAR = Fiat126P()

이제 CarFactory에서는 Fiat126P 이외의 자동차는 생산하지 못합니다.

 

만약 interface를 우리가 만들었다면 쉽게 해결할 수 있겠지만, 만약 외부 API라면 쉽게 해결할 수 없습니다.

 

리턴 타입은 API를 잘 모르는 사람들에게 전달해 줄 수 있는 중요한 정보입니다. 따라서 리턴 타입은 외부에서 확인할 수 있게 명시적으로 지정해주는게 좋습니다.

 


  • 타입을 확실하게 지정해야 하는 경우에는 명시적으로 타입을 지정해야 합니다.
  • 외부 API를 만들 때는 반드시 타입을 지정하고, 특별한 이유와 확실한 확인 없이는 제거하지 않습니다.