Nullable (Feat. Kotlin, C#)

Posted by 엘키의 주절 주절 on September 18, 2022

개요

Null 은 무엇인가?

없는 이란 뜻이며, 값을 보유하고 있지 않음을 의미한다.

Null은 값을 담고 있지 않기에, 없는 값을 읽으려 시도할 경우 C#, Java 등의 언어는 NullPointer Exception, NullReference Exception 등의 예외를 일으킨다.

값이 있을거라고 가정하고 작성한 코드가, 값이 없을 경우엔 의도와 다를 것이므로 예외가 발생하는 것은 납득이 된다.

하지만, 이에 대한 직관성이 떨어지기에 우리는 의식하거나, 습관이 되어 관성적이지 않는 이상 실수하기 쉽다.

제일 좋은 것은 Rust처럼 Null이 존재하지 않는 것이지만, C#과 Kotlin은 Null에 대해서 조금 더 나은 방법을 제공한다.

참고로 C#은 Project Property에 Nullable 을 true로 값을 주어야 Nullable에 대한 처리를 강화하고, Null 처리 누락시 경고를 처리해준다. 이 글에서는 C#의 경우 Nullable 옵션을 켰다고 가정한다.


Null을 다루는 방식

Null 검사가 없는 일반 타입

Java

자바에서는 아래 코드가, nullable 일 수도 있고, not null 일 수도 있다는 의미를 동시에 지닌다.

1
2
3
public int getLen(String str) {
    return str.lengh();
}

Kotlin

kotlin의 경우 별도의 표기가 없을 경우 not null 이므로 null 검사를 강제하지 않는다.

1
fun getLen(str: String)  = str.length

C#

마찬가지로 C#도 별도 표기가 없을 경우 null 검사를 하지 않아도 무방하다.

1
2
3
public int getLen(string str) {
    return str.lengh();
}

Nullable

null일 수 있음을 명확히 해주는 지시어다.

그래서 반드시 null 검사를 해주어야 한다.

Kotlin

1
2
fun getLen(s: String?): Int =
    if (s != null) s.length else 0

C#

1
2
3
public int getLen(string? str) {
    return str != null ? str.lengh() : 0;
}

Null safe operator

값이 있으면 해당 메서드 호출 결과 값, 없으면 해당 타입의 기본 값을 반환 한다.

주의 할 점은, 해당 함수 호출이 되지 않는 동작이므로, 반환 값에 대한 유의미한 검사가 동반되어야 할 경우도 있다.

Kotlin

1
2
3
4
5
6
7
8
9
fun printAllCaps(s: String?) {
    val allCaps: String? = s?.toUpperCase()
    println(allCaps)
}

fun main(args: Array) {
    printAllCaps("abc")
    printAllCaps(null)
}

C#

1
2
3
4
5
6
7
8
static void printAllCaps(String? s)
{
    var allCaps = s?.ToUpper();
    Console.WriteLine(allCaps);
}

printAllCaps("Hello, World!");
printAllCaps(null);

Elvis operator

값이 있으면 해당 값을 반환, 없으면 뒤에 넘어온 값을 반환한다.

Kotlin

1
2
3
fun getName(str: String?) {
    val name = str ?: "Unknown"
}

C#

1
2
3
4
static string getName(String? s)
{
    return s ?? "Unknown";
}

마치며

Null을 허용하는지 아닌지 명확해짐에 따라 코드가 훨씬 간결해짐을 알 수 있다.

또한 Null 검사가 누락 될 경우 경고/오류를 발생시키므로 훨씬 안전한 코드가 작성 됨을 알 수 있다.

언어적 표현력이라 함은 간결한 코드만 말하는 것이 아니라, 간결한 코드로 같은 동작을 해낼 수 있다는 의미다.

오늘 언급한 Null에 대한 표현력이 좋아진 것 만으로도, 훨씬 더 좋은 코드를 명확하게 작성할 수 있게 됐다.

오늘 언급한 부분을 포함한 좋은 표현력이, 코딩 과정의 만족도와 코드 리뷰의 효율을 증대 시켜서 Kotlin을 매력적으로 만들고 사용하는 회사와 개발자가 늘어나는 근거가 되는 것 같다.


참고