Dart 3.2 출시 소식

Dart 3.2 출시 소식

Dart 3.2를 발표해요. private final 필드의 논널 프로모션(non-null promotion)이라는 새 언어 기능, 새로운 인터럽(introperability) 기능으로 개선된 개발자 경험, DevTools에서의 확장(extension) 지원, 그리고 Wasm(WebAssembly) 지원을 담은 웹 로드맵 업데이트까지 — 이번 릴리스는 여럿이 함께 나아가요.

출처: Announcing Dart 3.2

본문

private final 필드의 논널 프로모션

Dart 2.12에서 sound null safety를 도입한 지 몇 년이 지났어요. null safety를 쓰면 어떤 타입이 nullable(값을 가질 수도 있고 null일 수도 있는)인지, 어떤 타입이 non-nullable(항상 값을 가지는)인지 선언할 수 있어요. null safety가 흐름 분석(flow analysis)과 결합되면, nullable 변수가 더 안전한 non-null 타입으로 "프로모션(promotion)"될 수 있는 시점을 감지해 줘요.

int definitelyInt(int? aNullableInt) {
  if (aNullableInt == null) {
    return 0;
  }
  // If flow analysis reaches this point,
  // aNullableInt can safely promote to a non-null int.
  return aNullableInt;
}

타입 프로모션은 Dart 2.12 때부터 null safety의 핵심이었지만, 로컬 변수에만 적용됐어요. 필드나 최상위 변수는 다음과 같은 경우에는 프로모션될 수 없었죠.

class Container {
  final int? _fillLevel;
  Container(this._fillLevel);
  check() {
    if (_fillLevel != null) {
      int i = _fillLevel; // Prior to Dart 3.2, causes an error.
    }
  }
}

이런 제약은 흐름 분석이 필드가 언제 어떻게 바뀔지 안전하게 판단할 수 없는 여러 복잡한 경우 때문이었어요. 예를 들어 클래스에서 필드를 프로모션할 때, 하위 클래스가 필드를 getter로 오버라이드하고 그 getter가 때때로 null을 반환한다면 문제가 생길 수 있었죠.

Dart 3.2에서 흐름 분석 엔진을 개선해서 이제 private final 필드를 타입 프로모션할 수 있게 됐어요. 이제 위 코드 스니펫은 오류 없이 통과해요. private이면서 final인 필드는 초기 할당 이후 값이 절대 바뀌지 않으므로, 한 번만 검사해도 안전하다는 점을 활용한 거예요. private final 필드 프로모션은 Dart 3.2부터 사용할 수 있고, Dart SDK의 하한(lower bound)이 3.2 이상인 프로젝트에 적용돼요.

package:lints 3.0의 새로운 코드 분석 옵션

코드 분석 얘기가 나왔으니, 표준 코드 분석 규칙인 package:lints도 여러 가지 개선됐다는 걸 말씀드릴게요. 이 패키지는 dart createflutter create로 새 프로젝트를 만들 때 함께 제공되는 기본·권장 정적 분석 규칙 세트를 담고 있어요. (package:flutter_lints — package:lints의 확장 — 를 통해서요.)

이 린트 세트의 새 주 버전인 3.0이 출시됐어요. 이번 개정에서 핵심 세트에 여섯 개, 권장 세트에 두 개의 린트가 추가됐어요. pubspec URL을 검증하고, 컬렉션 메서드를 올바른 인자로 호출하는지 검증하는 린트 등이 포함돼요. 전체 변경 목록은 changelog에서 확인할 수 있어요. 3.0은 다가오는 릴리스에서 새 프로젝트의 기본값이 될 거예요. 기존 프로젝트라면 지금 업그레이드할 수 있어요.

Dart 인터롭 업데이트

넓은 범위의 플랫폼에 걸친 멀티플랫폼 지원은 늘 Dart의 핵심 원칙이었어요. 그런데 한 줄의 Dart 코드가 모든 플랫폼에서 수정 없이 실행된다 해도, 큰 앱은 여전히 기존 코드와 인터롭해야 하는 경우가 많아요. 오래된 프로젝트의 코드일 수도 있고, 다른 라이브러리나 시스템 API에 있는 API일 수도 있죠. 이 분야에 여러 투자를 하고 있는데, 네이티브 C API와의 인터롭을 위한 FFI에서 시작했어요. 현재는 이를 Java와 Kotlin, Objective-C와 Swift 인터롭까지 확장하는 작업을 하고 있어요. JS 인터롭의 흥미로운 업데이트는 아래 Dart 웹 섹션에서 확인할게요.

Dart 3.2부터 네이티브 인터롭에 여러 가지 개선이 들어갔어요.

  • C FFI용 NativeCallable.isolateLocal 생성자를 도입했어요. 이 생성자는 임의의 Dart 함수로부터 C 함수 포인터를 만들어 줘요. 최상위 함수에서만 함수 포인터를 만들 수 있던 Pointer.fromFunction이 제공하는 기능을 확장한 거예요.

  • Objective-C 바인딩 생성기를 업데이트해서 Dart 3.1에서 추가한 NativeCallable.listener를 활용하도록 했어요. 이제 생성기가 Core Motion처럼 비동기 콜백을 포함한 API를 자동으로 처리할 수 있어요. 이런 API는 이전에 바인딩 코드 일부를 직접 작성해야 했죠.

  • Java·Kotlin 인터롭을 위한 package:jnigen을 계속 개선했어요. 덕분에 Android의 Cronet HTTP 클라이언트를 감싸는 package:cronet_http를 손으로 작성한 바인딩 코드에서 자동 생성된 래퍼로 옮길 수 있었어요.

  • Native Assets 기능도 크게 진전했어요. 네이티브 코드에 의존하는 Dart 패키지 배포와 관련된 여러 문제를 해결하려는 기능인데, Flutter와 독립 실행형 Dart 애플리케이션을 빌드할 때 관여하는 다양한 빌드 시스템과 통합하기 위한 균일한 훅을 제공해요. 미리보기는 문서에서 볼 수 있어요.

Dart 패키지용 DevTools 확장

Dart DevTools는 순수 Dart 앱과 Flutter 앱을 모두 지원하는 디버깅·성능 도구 모음이에요. Dart 3.2와 Flutter 3.16에서 새 확장 프레임워크발표했는데, 이 프레임워크를 쓰면 패키지 작성자가 자기 패키지를 위한 맞춤 도구를 만들어 DevTools에 바로 표시할 수 있어요. 프레임워크를 담은 pub.dev 패키지가 자신의 사용 사례에 특화된 맞춤 도구를 제공할 수 있게 되는 거죠. 예를 들어 Serverpod의 작성자들은 자기 패키지를 위한 개발자 도구를 열심히 만들고 있고, 다가오는 1.2 릴리스에서 DevTools 확장을 선보일 예정이에요.

Dart 웹과 Wasm 업데이트

Wasm(WebAssembly라고도 불러요)은 웹 브라우저를 위한 흥미로운 새 명령 형식이에요. 현대 브라우저에서 실행할 수 있는 휴대 가능하고 플랫폼 중립적인 바이너리 코드 형식을 제공하죠. Dart 같은 하이레벨 관리 언어는 가비지 컬렉션을 사용하는데, 이것이 Wasm 표준에 추가되고 있어요. Chrome 119부터 Wasm의 가비지 컬렉션 지원(Wasm-GC라고 불러요)이 기본으로 활성화됐어요. Wasm-GC 지원은 Firefox의 다음 안정 버전인 120에서도 옵니다. 그렇다면 Dart, Flutter, Wasm-GC는 어떤 상태일까요?

Dart-to-Wasm 컴파일러는 거의 기능 완성에 가까워요. 팀은 성능과 호환성에 매우 만족하고 있어요. 지금은 다양한 시나리오에서 빠른 출력을 보장하기 위해 엣지 케이스에 집중하고 있어요.

Flutter 웹의 경우 새로운 "Skwasm" 렌더링 엔진을 완성했어요. 성능을 극대화하기 위해, Skwasm은 컴파일된 애플리케이션 코드를 wasm-to-wasm 바인딩으로 커스텀 CanvasKit Wasm 모듈에 직접 연결해요. 또 Flutter 웹에서 처음으로 멀티스레드 렌더링을 지원하는 첫 단계이기도 해서, 프레임 시간이 더 개선됐어요.

Flutter 웹 + Wasm이 현재의 실험 상태를 벗어나려면 아직 몇 가지가 남아 있어요.

  • Dual compile(이중 컴파일): Wasm과 JavaScript 출력을 모두 생성하고, 런타임에 기능 감지(feature detection)를 활성화해서 Wasm-GC를 지원하는 브라우저와 그렇지 않은 브라우저를 모두 지원하는 것.

  • Modern JavaScript-interoperability(현대적 JS 인터롭): 확장 타입(extension types)에 기반한 새 JS 인터롭 메커니즘으로, JavaScript와 Wasm을 대상으로 할 때 Dart 코드·브라우저 API·JS 라이브러리 사이를 간결하고 타입 안전하게 호출할 수 있게 하는 것.

  • Browser APIs with Wasm support(Wasm 지원 브라우저 API): dart:html(및 관련 라이브러리)을 대체하는 새 package:web로, 현대적 JS 인터롭 메커니즘에 기반해요. JS와 Wasm 대상 모두에서 브라우저 API에 쉽게 접근할 수 있게 해줘요.

내부 프로젝트 여러 개를 package:web과 새 JS 인터롭 메커니즘으로 옮기기 시작했고, 다음 안정 릴리스에서 더 많은 업데이트가 있을 예정이에요. 그 사이 최신 세부 사항은 Support for WebAssembly 페이지에서 확인할 수 있어요.

마무리

오늘 준비한 내용은 여기까지예요. Dart 3.2는 지금 dart.dev에서 받을 수 있고, 오늘 발표된 Flutter 3.16 릴리스에도 포함돼 있어요. 다음에 또 만나요, Dart와 함께 즐거운 시간 되세요!

더 알아보기