Rlog

Kotlin Contract 본문

Kotlin

Kotlin Contract

dev_roach 2022. 10. 3. 17:08
728x90

Kotlin 을 사용하다 보면 유용한 확장함수들을 많이 만들어서 사용하게 되는데요. 이 확장함수를 사용하다 보면 "스마트 캐스트" 와의 문제에 부딪히고는 합니다. 한번 코드를 통해 Smart Cast 를 알아보도록 합시다.

Smartcast

위에서 설명한 예시를 코드로 보여주자면, 아래와 같은 상황인데요.

분명 isNotNull 이라는 제가만든 커스텀 확장함수로 NullCheck 를 함에도 불구하고 아래와 같이 `?(safe-null)` 을 써야만 하는 상황입니다. 이 상황은 왜 발생할까요? Kotlin 의 SmartCast 는 쉽게 얘기해서 컴파일러(Compiler) 가 Programmer 대신에 Casting 을 Smart 해주게 하는 기능을 뜻합니다. 즉, 위 코드가 SmartCasting 이 안되는 이유는 컴파일러에게 `given` 이라는 variable 이 not null 이라는 것이 전달되지 않았기 때문입니다.

 

이를 해결하기 위해서는 어떻게 해야할까요? 뭐 아주쉽게는 아래와 같은 방법으로 해결이 가능합니다.

하지만 위와 같은 해결 방법은 사실 단순하나.. 우리가 원하는 해결방법이 아닐뿐더러 확장함수에 적용되기는 힘든 방법입니다. 

그럼 어떤 방법을 사용해야 할까요?

Contract

위와 같은 문제로 인해서 Kotlin 1.3 에서는 Contract 라는 개념을 도입했습니다. Contract 는 Compiler 에게 어떤 행위에 대한 결과값이 trusy 한지 falsy 한지를 알려주어 Smartcast 를 가능하도록 하는 기능인데요. 아까의 코드를 보면 조금 더 이해가 쉬우니, 아까의 코드에서 isNotNull() 의 구현체 부분을 다시 보도록 합시다.

isNotNull 함수는 현재 위처럼 구현되어 있는데요. 해당 변수가 Null 이 아님을 체크하는 Function 입니다. 이를 contract 를 사용하여 바꿔보도록 합시다.

위와 같이 코드를 변경해주면 되는데요. 쉽게 예기해서 "현재 객체가 null 이 아닐경우 true 를 리턴할꺼야" 라고 컴파일러에게 얘기해주는 코드입니다. 해당 기능은 실험적인 기능임으로, @OptIn(ExperimentalContracts::class) 을 명시해주어야 합니다. 

위와 같이 코드를 변경한 뒤, 아까의 코드를 다시 실행시켜 보도록 합시다.

이제 ?(null-safety) 를 쓰지 않아도 컴파일 에러가 나지 않는 것을 확인할 수 있습니다. 즉, 우리가 전달하고자 하는 정보가 Compiler 에게 잘 전달되었음을 의미합니다.

마치며

코틀린을 사용하다보면 이걸 왜 Smartcast 못해줘! 라는 느낌을 받은적이 많으실텐데요. 그 경우 Contract 기능을 이용하여 해소하는 방법을 이용하면 됩니다. 사실 코틀린 내장 메소드에서 저런 답답함을 해소해주는 것(`filteredIsInstance` 와 같은 메소드)들도 존재해서 잘 살펴본 뒤, 사용하시는 것들을 추천드립니다.