Kotlin

[TIL] 코틀린에서 Unit이란 타입을 만든 이유가 무엇일까?

안덕기 2022. 3. 17. 20:56

이 글은 facebook에서 kotlin study 그룹을 이끌고 계신 그룹장님과 kotlin in action의 역자분께 질문 드린 내용을 정리하였습니다. 그리고 코틀린 인 액션의 내용을 많이 참고하였습니다.

 

코틀린 완벽 가이드라는 책을 읽다가 문득 이런 생각이 났다. 왜 코틀린은 Void 라는 클래스를 사용하지 않고 Unit 라는 타입을 새로 만들었을까? 아무리 생각해봐도 찾아보다 내가 아는 지식 안에서는 답이 나오지 않아서 kotlin study에 질문을 올렸다.

내가 완벽하게 이해한 것이 아니기 때문에 틀린 내용이 있을 수 있지만 코틀린이 가진 철학을 다시 살펴볼 수 있는 내용인 것 같아 정리해보려고 한다.

현대 언어에서의 프로시저

현대 언어에서는 프로시저를 가르키는 예약어가 존재하지 않지만 베이직등 예전 언어에서는 프로시저를 지칭하는 예약어가 존재했다. 함수와 프로시저의 가장 큰 차이는 프로시저는 반환 값이 없어도 되지만 함수는 반드시 반환 값을 가지고 있어야 한다. 그런데 A,B,C 등의 언어부터는 프로시저와 함수를 예약어로 같은 것으로 퉁치기 시작했다. 하지만 프로그래밍 언어론적으로는 프로시저와 함수는 확연히 구분이 된다. 왜냐하면 함수를 호출하는 포인트에서 값을 반환할지 말지 결정되어 컴파일이 되기 때문이다.

자바에서는 이 프로시저를 구현하는 방법을 반환 값이 void인 함수로 디자인이 되었다. 결국 void 라는 예약어는 컴파일러에게 그냥 프로시저로 해석하라는 의미가 된다. 클래스도 아니고 인스턴스도 아니다.

Unit이 가지는 의미

프로시저의 유산인 void는 어떤 타입을 지칭하는 것이 아니다보니 함수를 타입으로 사용할 때 void 라는 것은 걸림돌이 되었다. 예를 들어 다음과 같은 코드가 아예 불가능하다.

val hashMap = HashMapOf<() -> Void>() // Void 때문에 안됨

다시 한번 말아면 Void는 형이 아니기 때문에 형 비교가 불가능하다. 그래서 언어를 만드는 사람 입장에서는 void 라는 것이 거슬렸을거고 코틀린에서 프로시저라는 개념을 아예 없애고 함수만 존재하는 형태로 된 것이다. 대신 아무것도 반환하지 않는 것에 대해 Unit이라는 타입이자 싱글톤인 값을 사용하게 된 것이다.

참고로, 자바스크립트도 프로시저를 없애기 위해 undefined 라는 것을 도입해서 사용하고 있다.

Unit의 컴파일

코틀린 코드를 JVM으로 컴파일하면 Unit은 다음과 같이 두가지 경우로 컴파일이 된다.

  • 함수의 반환 타입이 Unit이고 함수가 제네릭 함수를 오버라이드하지 않는다면 자바로 컴파일될 때 void 함수로 컴파일된다.
  • 그게 아니면 Unit으로 컴파일된다.

즉, Unit을 제네릭 타입 인자로 사용하지 않는 이상 void로 컴파일된다는 의미다. 코틀린에서 타입 인자에 타입 인자 없음을 구현하기 위해서는 Unit이라는 새로운 타입을 추가하는 것이 훨씬 간편했을 것이다.

 

내가 이해한 것을 요약하면 다음과 같다.

  • void는 프로시저를 표현하기 위한 자바의 정책이다.
  • void는 타입이 아니기 때문에 제네릭의 타입인자로 활용할 수 없다.
  • 코틀린는 이를 해결하기 위해 Unit이라는 타입을 도입했고 자바로 컴파일 하는 과정에서 어느정도 최적화를 한다.
  • Unit 뿐만 아니라 Nothing 같이 프로그래밍적으로 유용한 타입을 제공해준다.