Flutter 2.0 Sound Null Safety 깊이 파헤치기

nerdrun
9 min readApr 4, 2021

Flutter 2.0이 출시된 지 벌써 많은 시간이 흘렀습니다. 기존의 Unsound Null Safety version을 사용해오신 개발자들은 Flutter 2.0 출시 후 기존 프로젝트를 Null Safety Version으로 Migration 하시느라 바쁜 하루를 보내셨을 거 같습니다.

오늘날, Kotlin, Swift, Rust 등 다양한 언어에서 각 언어마다 다른 방식으로 null에 대한 문제를 해결해오고 있습니다. null 참조 개발은 수조원 달러의 실수를 야기했다라고 할 정도입니다. 관련 영상은 이 링크를 참조해주세요.

Null Safety 간단 개요

Null Safety 문법 소개

Null Safety에 대한 문법 중 가장 사용 빈도가 높은 부분만 간추려서 나열해보았습니다.

아래의 코드는 Null Safety가 적용된 문법이고 각 변수들은 절대 null 할당을 허용하지 않습니다. (Null Safety version)

아래는 Nullable Type으로 null을 허용하는 Type입니다. “?” 라는 새로운 Syntax가 생겼고 바로 Type 뒤에 물음표를 붙이므로써 해당 Type은 null을 할당할 수 있게 됩니다. (mixed-version)

그렇다면, 아래의 코드는 에러가 발생할까요?

final String? favouriteSport; 같은 경우는 null을 허용하는 Nullable Type이므로 생성자의 favouriteSportnull을 전달해도 error가 발생되지 않습니다.

반면에 final String name; 같은 경우는 Non-Nullable Type이므로 null을 허용하지 않습니다. 생성자의 name 에 값을 삽입하더라도 required라는 키워드를 반드시 삽입해줘야 에러가 발생하지 않습니다. 기존의 annotation @required 가 아닙니다.

예, 이제 compiler가 error를 발생시키지 않게 되었습니다. 또, 아래와 같이 favouriteSport의 값을 아예 주지 않아도 에러가 발생하지 않습니다.

물론 name에 대한 ‘Todos’ 값을 삭제하면 error가 다시 발생하겠죠.

그렇다면 이런 경우에는 어떨까요?

정의된 메소드 getTodo()의 파라미터는 Non-Nullable TypeString Type이지만, 전달하는 todo의 타입은 Nullable TypeString? Type이므로 에러가 발생하게 됩니다.

위와 같은 경우는 총 3가지 방법으로 핸들링할 수 있습니다.

  1. null 확인하기

그동안 가장 많이 사용한 방법인 null이 아닐 경우에만 getTodo()를 호출하는 방법.

2. null 일 경우 다른 값을 전달하기.

3. ! Syntax를 사용하여 이 값은 절대 null 될 수 없음을 선언하기

변수 뒤에 ! 를 붙이므로서 해당 변수는 절대 null 될 수 없다고 선언합니다. 만약 코드를 작성할 때 확실히 해당 변수가 null 될 수 없다는 걸 알면 사용할 수 있습니다. 다만, error를 피하기 위해 !를 사용하게 되면 Runtime 에서 Null Exception이 발생할 수 있습니다.

또한, 아래와 같이 return의 명시된 methods가 return이 없다면 error가 발생합니다.

지금까지 Null Safety의 문법에 대한 예시를 몇 가지 전달드리며 Non-Nullable TypeNullable Type의 동작 원리에 대해 간단히 설명드렸습니다. 위의 내용만 이해하더라도 Null Safety 가 적용된 새로운 Dart에서 코드를 작성하시기 더욱 수월해지실 겁니다.

이제부터 아래의 글은 Null Safety에 조금 더 깊이 알고 싶으신 분들에게 권장합니다.

Null Safety 조금 더 깊이 파보기

Null Safety는 왜 필요할까?

Dart 정규 사이트에도 나와있지만

위와 같은 코드를 실행하면 isEmpty() 로 전달받은 Stringnull이기에 .length를 호출에서 NoSuchMethodError 예외가 발생하게 됩니다. 이와 같은 경우는 compile 단계에서 IDE에 의해 에러를 미연에 잡아주면 좋겠지만, 사실 위의 코드는 Runtime에 에러가 나게 됩니다.

Null Safety가 도입된 이유 중 가장 큰 이유는 우선 null에 의한 참조 에러를 미연에 방지하기 위함입니다. 더 쉽게 발견하고 더 쉽게 코드를 고칠 수 있게 된 겁니다.

또 다른 이유로는 compiler가 Null Safety가 확정인 모든 properties 에 대해 null checker를 굳이 호출하여 확인할 필요가 없어지므로 코드, binary 코드 생성 및 코드 실행 속도 또한 상당히 빨라지게 됩니다.

기존의 Nullable Type과 Non-Nullable Type의 차이점은?

Dart는 기본형 타입 (primitive type) 또한 Object에서 상속되었고 각각의 객체는 고유의 methods를 가지고 있는 있습니다. 이 부분은 현재 Null Safety Dart version과 차이가 없습니다.

다만 Null Safety가 존재하기 전의 모든 정적 타입은 null을 허용했기 때문에 Null Type은 아래와 같이 모든 Type의 subtype이었습니다.

https://dart.dev/null-safety/understanding-null-safety/hierarchy-before.png

위의 구조처럼 Iterable을 상속받은 List.add() 메소드를 사용할 수 있게 되고, doubleintnum을 상속받았기 때문에 +를 호출할 수 있는 것입니다. 그러나 null을 허용하기 때문에 .add(), + 와 같은 메소드를 전혀 참조할 수 없기 때문에 null 참조 에러가 발생할 수 있습니다.

반면에 Non-Nullable Type은 가장 최상위의 상속 구조를 변경하므로써 해당 문제를 제거할 수 있게 됩니다. Null Type은 여전히 존재하지만 아래 그림과 같이 모든 Type의 subtype으로 존재하지 않습니다.

https://dart.dev/null-safety/understanding-null-safety/hierarchy-after.png

이번 Dart Version에서는 기본적으로 모든 타입을 Non-Nullable Type으로 만들어놨습니다. 따라서 double은 반드시 double만을 허용하고, int는 반드시 int만을 허용하게 됩니다.

개요에서 설명한 코드 중에서 아래의 코드가 에러가 발생하는 이유는

기본적으로 Non-Nullable Type은 반드시 Non-Nullable Type만을 할당 받을 수 있기 때문입니다.

그러나 만약 반대로 Nullable Type은 Non-Nullable Type과 Null Type 2가지 타입 전부다 할당 받을 수 있으니 아래의 코드는 에러가 없이 잘 작동하게 됩니다.

https://dart.dev/null-safety/understanding-null-safety

그렇다면 Null Safety version에서는 Null을 전혀 사용하지 않는가?

Dart측도 Null Type은 여전히 유용하기 때문에 사용하도록 권장합니다. 해당 Syntax로는 Type? 과 같은 “?” 를 사용하므로서 Null이 가능한 Type인 Nullable를 만들어주었습니다. (기존에 있던 저희가 사용하던 코드에서 약간 문법을 변형시켰습니다.)

Dart는 현재 Null Safe version 에서 제공하는 문법을 완전하게 사용했을 때만 Null Safety로 간주합니다. 즉, 우리가 기존에 사용하던 문법(Legacy code)을 사용하면 mixed-version을 사용하는 것입니다.

다만 우리가 완전하게 null이 될 수 있음을 감지하고 코드를 작성한다면 Nullable를 사용해도 실제로 문제가 없는 것이죠.

마치며

Null Safety의 전체적인 개요부터 약간 깊숙한 내용까지 살펴보았습니다. 물론 더 깊은 내용이 있으나, 해당 내용을 다루기에는 글이 매우 길어질 것 같아 여기서 마무리 지으려고 합니다. 더 깊이 내용을 알고 싶으신 분은 해당 링크를 클릭하셔서 두루 살펴보시길 바랍니다.

참고자료

Dart Official Null Safety — https://dart.dev/null-safety/understanding-null-safety

Youtube: Tadas Petra — https://www.youtube.com/watch?v=_VrulBiOV_o

--

--

nerdrun

Flutter for an app, Vue for an web, nodeJs for a server, Linux