Null

내위키

사전에서 찾아보면 '아무런 가치가 없는 것'을 뜻하는 형용사다.

컴퓨터 프로그래밍에서 자주 만나볼 수 있는 값이자, 온갖 버그를 일으키는 만악의 근원으로 찍혀 있는 값이기도 하다.

0과는 다르다. 0이라는 것은 정수든 부동소수점이든 0이라는 '값'을 뜻하지만 Null은 그냥 아무 값이 없는 값을 뜻한다.

비슷한 뜻을 가진 명사인 'nil'을 사용하는 언어도 있다. Go, Lua, LISP 같은 언어들이 nil을 사용한다. 파이썬은 None을 사용한다.

굉장히 남용하기 쉽다. 예를 들어 어떤 함수가 포인터 혹은 객체의 결과값을 돌려줘야 하는데 내부에서 오류가 일어났다든가, 처리에 실패했다든가 해서 돌려줄 값이 없다면? 그냥 편하게 null을 돌려주면 된다. 객체 유형의 변수를 정의했는데 실제 변수에 들어가는 값은 이후 처리를 통해 만들어진다. 그럼 변수 초깃값으로 뭘 주지? 그냥 null을 넣자. 이래저래 뭐 넣거나 돌려줄 게 마땅치 않으면 속 편하게 null로 해결하면 된다.

10억 달러짜리 실수

오죽하면 알골 언어를 디자인하면서 널 값을 처음으로 고안했던 Null의 아버지 토니 호어가 이를 두고 'The Billion Dollar Mistake(10억 달러짜리 실수)'라고 할 정도다. 알골을 선언할 때 아직 변수가 들어갈 값이 없는 상황을 좀 쉽게 해결하자는 마음에 널 참조를 허용했는데 이 때문에 수십 년 동안 일어난 문제가 'billion dollar' 수준으로 손해가 될 만큼 엄청나다는 것을 뜻하는 말.

문제는 이 값을 사용하는 쪽에서 종종 벌어진다. 예를 들어 함수를 사용하는 쪽에서 null 값이 왔는지 제대로 체크하지 않고 값을 쓰면 오류가 터진다. 변수 역시도 null 상태인 녀석을 그냥 썼다가 역시 오류가 터지는데, C처럼 포인터의 자유도가 높은 언어라면 그야말로 무슨 일이 터질지 모르는 시한폭탄을 들고 있는 것이나 마찬가지다. 객체지향 언어로 프로그래밍하는데 클래스 객체를 정의만 해놓고 초깃값을 null로 했는데 코드의 다른 곳에서 아직 null 상태인 객체의 메서드나 필드를 부르면? 이 역시 오류 확정이다. 자바 프로그래머라면 아마도 런타임에서 NullPointerException 예외를 지긋지긋하게 볼 것이고 다른 언어도 이와 비슷한 null 참조 오류 때문에 디버깅 하느라 머리가 깨진다. 프로그래머가 아닌 사용자도 잘 쓰던 프로그램이 갑자기 오류를 토해내면서 다운되는 바람에 작업을 날려먹는 일이 있을 텐데 오류 메시지를 살펴보면 대부분 null 참조 문제다.

Null 참조 문제를 컴파일 단계에서 잡아내면 좋지만 대부분 컴파일은 그냥 되고 런타임에서 오류가 터진다. Null 여부를 꼼꼼하게 처리하면 되는 거잖아, 하고 생각할 수 있지만 프로그램의 덩치가 커질수록 그렇게 꼼꼼하게 체크하는 게 쉬운 일도 아니며, 함수 하나 쓸 때마다, 변수 하나 쓸 때마다 일일이 if 문으로 null 여부를 확인하는 것도 쓸데없는 코드가 너무 많아진다. 특히 남이 만든 함수나 라이브러리를 사용할 때 문서화가 제대로 안 되어 있으면 멋모르고 썼다가 버그와 오류가 발생한다. 그래서 null 값을 고안했던 토니 호어가 'The Billion Dollar Mistake'라고 한 것이다.

널 안전성

최근의 언어들은 이러한 null 문제를 줄이기 위해 널 안전성에 신경을 쓰고 있다. 전략은 대략 다음과 같다.

  • 변수에 null을 대입하지 못하게 한다. 쉽게 말해 원천봉쇄. 불가피한 경우에만 명시적으로 변수를 정의할 때 null 값을 쓸 수 있다고 명시한다. 이런 변수를 nullable(null+able)이라고 한다. 예를 들어 코틀린은 데이터 유형 뒤에 ? 기호를 붙여줘야, 예를 들어 var foo: String? 처럼 해야 nullable로 쓸 수 있다.
  • null 값인 경우 참조를 하지 않는 연산자를 제공한다. 예를 들어 코틀린foo?.doSomething() 코드를 실행시키면 foo 객체가 null이 아닐 때에만 doSomething() 메서드를 실행시킨다.
  • 또한 null 값인지 여부에 따라 처리를 다르게 하는 연산자를 통해 null 여부 체크를 위한 코드가 길어지지 않게 도와주기도 한다.

코틀린, Swift, Dart와 같은 언어들은 null 값을 허용하지만 각자의 방법으로 널 안전성을 지원한다. Dart도 널 안전성을 지원하긴 하지만 좀 반쪽짜리인 느낌이 있는데, 1.22부터는 변수를 기본으로 non-nullable로 하는 것을 비롯해서 코틀린 수준의 널 안전성을 제공한다고 예고하고 있다.

각주