reified로 알아보는 Kotlin Generic

김정원
4 min readJan 8, 2023

--

얼마 전에 이런 코딩하면서 코드에 이런 빨간줄이 생기는 걸 보았다.

왜 제네릭으로 타입 캐스팅을 하려는데 안되는 것이었다. 에러 메시지를 확인해보니 아래처럼 보여졌다.

Cannot use 'P' as reified type parameter. Use a class instead.

P는 reified type parameter 로 사용할 수 없다는 것이다.
reified 가 뭘까? 왜 reified type parameter 가 아니면 사용하지 못할까?

Generic 을 컴파일하면 생기는 일

구글링을 해보니 reified 는 런타임에서 인자의 타입에 대한 정보를 알고 싶을때 사용한다고 되어 있었다. 즉, Generic은 런타임에서 제네릭 타입을 알 수 없다는 의미이다.

왜 그럴까?

이를 이해하려면 제네릭이 컴파일되고 런타임에서 실행이 될때 무슨일이 일어나는지 이해해야한다.

다음의 예제로 설명해보도록 하겠다.

public static  <E> boolean containsElement(E [] elements, E element){
for (E e : elements){
if(e.equals(element)){
return true;
}
}
return false;
}

위 코드는 제네릭을 인자로 받아 배열에서 특정 요소가 있는지 여부를 체크하는 함수이다. 이 코드에서 Generic E 는 현재 어떤 타입인지 정해지지 않았다. (이 함수가 실행될때까지 아무도 어떤 타입인지 모른다) 그렇다면 이 코드가 컴파일 되게 하려면 어떻게 해야할까?

바로 Type erasure 를 하면 된다.

Type erasure

Type erasure 란 모든 제네릭 타입 인자를 bounded type 또는 unbounded type 으로 바꿔는 것을 말한다. (사실 바꾸면서 부가적으로 하는 일들이 몇가지 더 있다)

위 코드를 Type erasure 해보면 다음과 같다.

public static boolean containsElement(Object [] elements, Object element){
for (Object e : elements){
if(e.equals(element)){
return true;
}
}
return false;
}

Generic type parameter EObject (최상위 객체 클래스) 로 바뀌는 것을 볼 수 있다. (아마도 Generic Type 이 사라졌기 때문에 타입 소거라 한게 아닌가 싶다)

reified 란?

만약 타입 소거로 인해 알수 없게 된 타입 인자의 타입에 대해 알고 싶다면 어떻게 해야할까?

직접 인자에 Class<T> 를 넘겨줘도 되지만 이러면 가독성이 떨어질 수도 있다. (이런 함수를 만들어야 될지도 모른다)

fun <T> doSomething(someValue: T, Class<T> type)

하지만 kotlin 에서는 reified 라는 키워드를 사용하면 Class 인자를 전달하지 않아도 런타임에서 어떤 타입인지 알 수 있게 된다. (아래 코드에서 inline 키워드를 사용하는 이유는 제네릭 타입 인자를 사용할 때 발생하는 오버헤드를 줄이기 위해 사용하는 키워드이다)

inline fun <reified T> doSomething(someValue: T)

마무리

처음에 아무 생각 없이 사용하던 제네릭이 reified 키워드를 통해 여러 일들이 이루어진다는 것을 알 수 있었다.

Reference

--

--

김정원

Android Developer who loves programming and sharing dev knowledge