Dart 언어 발전사

Dart 언어 발전사 (Dart language evolution)

Dart 프로그래밍 언어에 추가되거나 바뀐 주목할 만한 내용들을 버전별로 정리한 페이지예요.

출처: Dart 공식 문서 - Dart language evolution

본문

2.0 이후에 도입된 언어 기능을 쓸 때는, 해당 기능을 Dart가 처음 지원한 릴리스를 SDK 제약(constraint)의 하한으로 설정해야 해요.

예를 들어 2.12에서 도입된 null safety를 쓰려면 pubspec.yaml 파일에 2.12.0을 하한으로 설정하면 돼요.

environment:
  sdk: '>=2.12.0 <3.0.0'

각 릴리스에서 다루는 더 자세한 변경 내용은 SDK 체인지로그(changelog)와 Breaking changes 페이지를 참고해 주세요.

릴리스별 변경 사항 (Changes in each release)

Dart 3.13

2026년 8월 12일 릴리스 | Dart 3.13 공지

Dart 3.13은 primary constructors를 도입했어요. 생성자와 그 인스턴스 변수를 선언 헤더에 직접 선언할 수 있는 간결한 문법이죠.

class Point(var int x, var int y);

primary constructors는 필드 선언, 매개변수 전달, 생성자 본문에서의 할당이라는 보일러플레이트를 줄여줘요. 런타임 동작을 바꾸는 게 아니라 선언을 쓰는 방식만 바꾸는 기능이에요.

Dart 3.13은 또한 클래스 본문에 선언된 생성자를 위한 간결한 생성자 문법을 추가했어요. 클래스 이름을 반복하는 대신 newfactory를 쓰면 되죠.

이 릴리스는 dart format의 출력에 대한 언어 버전별 변경 사항도 포함해요.

  • extension type 표현 절(representation clause)을 나눌 때 후행 콤마(trailing comma)를 추가해요.
  • 최적이 아닌 줄 분할을 피하도록 eager splitting을 개선해요.
  • 단일 요소 대상을 가진 호출 체인을 분할하는 것을 선호해요.
  • 매개변수 목록에 블록 포맷팅을 허용해요.
  • as, is, is! 표현식에 블록 포맷팅을 허용해요.
  • import 구분을 서로 다른 섹션으로 나눠요.
  • 규칙이 블록 포맷팅을 사용할 때 if-case 가드(guard)를 분할해요.
  • 페이지 너비에 맞는 포맷팅 해법이 없을 때, 문자열 리터럴이나 주석으로 끝나는 줄넘침을 선호해요.
  • ; 본문이 없는 믹스인과 extension type 선언 주위에 빈 줄을 추가해요.

이 변경 사항과 추가 변경 사항에 대한 자세한 내용은 Dart 3.13 체인지로그를 참고해 주세요.

Dart 3.12

2026년 5월 18일 릴리스 | Dart 3.12 공지

Dart 3.12는 **private 이름 있는 매개변수(private named parameters)**를 도입했어요. initializing formal parameters를 통해 private 필드를 직접 초기화할 수 있게 해주죠. 이전에는 이름 있는 매개변수로 private 필드를 초기화하려면 생성자의 초기화 리스트에서 수동으로 할당해야 했어요.

이제 initializing formal parameter가 private 필드를 가리키면, Dart가 매개변수의 공개 이름을 만들기 위해 앞의 밑줄(_)을 떼어내요. 그래서 호출자는 호출 지점에서 접두어 없는 이름을 쓸 수 있죠.

class Point {
  final int _x;
  final int _y;

  Point({required this._x, required this._y});
}

void main() {
  // Callers use the public, unprefixed names of the parameters.
  final point = Point(x: 1, y: 2);
}

Dart 3.11

2026년 2월 9일 릴리스 | Dart 3.11 공지

Dart 3.11은 새로운 언어 기능은 없지만, Dart 3.10에서 도입된 dot shorthand 문법에 대한 분석기와 편집기 지원을 몇 가지 개선했어요.

Dart 3.10

2025년 11월 12일 릴리스 | Dart 3.10 공지

Dart 3.10은 dot shorthand를 도입했어요. enum 값, static 멤버, 또는 생성자에 접근할 때 명시적 타입 이름을 생략할 수 있는 간결한 문법이죠. 컴파일러가 문맥에서 타입을 추론할 수 있다면, 전체 ContextType.foo 대신 그냥 .foo를 쓰면 돼요.

// Use dot shorthand syntax on enums:
enum Status { none, running, stopped, paused }

Status currentStatus = .running; // Instead of Status.running

// Use dot shorthand syntax on a static method:
int port = .parse('8080'); // Instead of int.parse('8080')

// Uses dot shorthand syntax on a constructor:
class Point {
  final int x, y;
  Point(this.x, this.y);
  Point.origin() : x = 0, y = 0;
}

Point origin = .origin(); // Instead of Point.origin()

Dart 3.9

2025년 8월 13일 릴리스 | Dart 3.9 공지

Dart 3.9에서 다음 지원 기능들이 업데이트됐어요.

name: my_app
environment:
  sdk: ^3.9.0
  flutter: 3.33.0
  • Null safety: 이제 Dart는 타입 승격, 도달 가능성(reachability), 확정 할당(definite assignment)을 계산할 때 null safety를 가정해요. 이 변경으로 인해 더 많은 dead_code 경고가 발생할 수 있어요.
  • Flutter 상한 버전이 존중됨: 언어 버전 3.9부터, 루트 패키지에서 flutter SDK 제약의 상한이 존중돼요. 예를 들어 위 pubspec.yaml과 같은 제약이 있으면 3.33.0과 다른 버전의 Flutter SDK로 dart pub get을 호출하면 실패해요. 다만 의존성으로 사용되는 패키지에서는 flutter 제약의 상한이 여전히 무시돼요.

이 변경 사항과 추가 변경 사항에 대한 자세한 내용은 Dart 3.9 체인지로그를 참고해 주세요.

Dart 3.8

2025년 5월 20일 릴리스 | Dart 3.8 공지

Dart 3.8에 다음 언어 기능이 추가됐어요.

  • Null-aware 요소 (Null-aware elements): null-aware 요소는 컬렉션 리터럴에서 표현식을 평가하고, 결과가 null이 아니면 그 값을 둘러싼 컬렉션에 삽입해요.

이 지원 기능들이 업데이트됐어요.

  • Dart format: Dart 3.8의 포매터는 이전 릴리스의 재작성을 바탕으로 피드백, 버그 수정, 추가 개선을 통합했어요. 이제 후행 콤마 배치를 지능적으로 자동화해서, 구성을 강제하는 대신 분할 여부를 결정해요. 업데이트는 코드 출력을 개선하기 위한 스타일 변경도 포함해요.

자세한 내용은 Dart 3.8 체인지로그를 참고해 주세요.

Dart 3.7

2025년 2월 12일 릴리스 | Dart 3.7 공지

Dart 3.7은 언어에 와일드카드 변수(wildcard variables) 지원을 추가했어요. 와일드카드 변수는 이름이 _인 지역 변수나 매개변수예요. 와일드카드 변수는 **비바인딩(non-binding)**이므로 충돌 없이 여러 번 선언할 수 있어요. 예를 들어:

Foo(_, this._, super._, void _()) {}

dart format 명령도 3.7부터 언어 버전에 연결돼요. 입력 파일의 언어 버전이 3.7 이상이면 코드가 새로운 tall style로 포맷돼요. 새 스타일은 인자 목록에 후행 콤마를 추가했을 때 얻는 스타일과 비슷한데, 이제 포매터가 그 콤마들을 알아서 추가하고 제거해줘요. 인자나 매개변수 목록이 분할되면 이렇게 포맷돼요.

longFunction(
  longArgument,
  anotherLongArgument,
);

자세한 내용은 체인지로그에서 확인할 수 있어요.

Dart 3.6

2024년 12월 11일 릴리스 | Dart 3.6 공지

Dart 3.6은 언어에 숫자 구분자(digit separator) _ 지원을 추가했어요. 숫자 구분자는 긴 숫자 리터럴의 가독성을 높여줘요.

var m = 1__000_000__000_000__000_000;

Dart 3.5

2024년 8월 6일 릴리스 | Dart 3.5 공지

Dart 3.5는 새 언어 기능은 추가하지 않았지만, 타입 추론 중 고려하는 문맥에 사소한 변경을 가했어요. 언어 버전과 무관한(non-language versioned) 이 변경들은 다음을 포함해요.

  • await 표현식의 문맥이 dynamic일 때, 표현식의 피연산자에 대한 문맥이 이제 FutureOr<_>가 돼요.
  • 전체 if-null 표현식(e1 ?? e2)의 문맥이 dynamic일 때, e2의 문맥이 이제 e1의 static 타입이 돼요.

Dart 3.4

2024년 5월 14일 릴리스 | Dart 3.4 공지

Dart 3.4는 타입 분석 관련 몇 가지 개선을 만들었어요. 다음을 포함해요.

  • 조건식, if-null 표현식과 할당, 그리고 switch 표현식의 타입 분석을 개선했어요.
  • cast 패턴의 패턴 문맥 타입 스키마를 명세와 일치시켰어요.
  • null-aware spread 연산자(...?)의 타입 스키마를 목록 리터럴의 동작에 맞추기 위해 맵과 셋 리터럴에서 nullable하게 만들었어요.

Dart 3.3

2024년 2월 15일 릴리스 | Dart 3.3 공지

Dart 3.3은 언어에 몇 가지 개선을 추가했어요.

  • Extension types는 Dart의 새 기능으로, 기존 타입을 제로 비용으로 감싸는(wrapping) 것을 허용해요. 래퍼 클래스와 확장 메서드와 비슷하지만, 구현 차이와 서로 다른 트레이드오프가 있어요.
extension type Meters(int value) {
  String get label => '${value}m';
  Meters operator +(Meters other) => Meters(value + other.value);
}

void main() {
  var m = Meters(42); // Has type `Meters`.
  var m2 = m + m; // OK, type `Meters`.
  // int i = m; // Compile-time error, wrong type.
  // m.isEven; // Compile-time error, no such member.
  assert(identical(m, m.value)); // Succeeds.
}
  • 충돌하는 선언이 없다면, 추상 getter가 이제 private final 필드 승격 규칙에 따라 승격(promotable)될 수 있어요.

Dart 3.2

2023년 11월 15일 릴리스 | Dart 3.2 공지

Dart 3.2는 흐름 분석(flow analysis) 개선을 추가했어요.

  • 확장된 타입 승격: 이제 private final 필드에도 타입 승격이 동작해요. 이전에는 지역 변수와 매개변수에서만 가능했는데, 이제 private final 필드는 null 검사와 is 테스트를 통해 non-nullable 타입으로 승격될 수 있어요. 예를 들어 다음 코드가 이제 sound해요.
class Example {
  final int? _privateField;

  Example(this._privateField);

  void f() {
    if (_privateField != null) {
      // _privateField has now been promoted; you can use it without
      // null checking it.
      int i = _privateField; // OK
    }
  }
}

// Private field promotions also work from outside of the class:
void f(Example x) {
  if (x._privateField != null) {
    int i = x._privateField; // OK
  }
}
  • 매치 대상 값이 예외를 던지는 if-case 문의 타입 승격 동작에서의 불일치를 수정했어요.

private final 필드가 언제 승격될 수 있고 될 수 없는지에 대한 자세한 내용은 'Fixing type promotion failures'를 참고해 주세요.

Dart 3.1

2023년 8월 16일 릴리스 | Dart 3.1 공지

Dart 3.1은 새 기능을 추가하지 않았고 언어에 대한 변경도 없었어요.

Dart 3.0

2023년 5월 10일 릴리스 | Dart 3.0 공지

Dart 3.0은 몇 가지 주요 새 언어 기능을 도입했어요.

  • 패턴 (Patterns): 값을 매치하고 구조 분해할 수 있는 새 문법 범주예요.
  • 레코드 (Records): 여러 타입의 값을 함수 하나의 반환에 묶을 수 있는 새 타입이에요.
  • 클래스 수식어 (Class modifiers): 클래스나 믹스인이 어떻게 쓰일 수 있는지 제어하는 새 키워드 집합이에요.
  • Switch 표현식 (Switch expressions): 표현식이 기대되는 곳에서 허용되는 새 다중 분기 형태예요.
  • If-case 절 (If-case clauses): 값을 패턴에 매치하고, 패턴 매치 여부에 따라 then 또는 else 분기를 실행하는 새 조건 구성이에요.

Dart 3.0은 또한 몇 가지 **파괴적 언어 변경(breaking changes)**을 도입했어요.

  • mixin 클래스 수식어가 없는 클래스 선언은 더 이상 믹스인으로 적용될 수 없어요.
  • 선택적 이름 있는 매개변수의 기본값 앞의 구분자로 콜론(:)을 쓰는 것은 이제 컴파일 타임 오류예요. 대신 등호(=)를 쓰세요.
  • continue 문이 루프 문(for, do, while)이나 switch 멤버에 붙어 있지 않은 레이블을 대상으로 하면 이제 컴파일 타임 오류예요.

Dart 2.19

2023년 1월 25일 릴리스

Dart 2.19는 타입 추론과 관련된 몇 가지 예방 조치를 도입했어요. 다음을 포함해요.

  • 도달할 수 없는 코드 경우에 대한 더 많은 흐름 분석 플래그
  • 접근할 수 없는 private 이름을 더 이상 noSuchMethod에 위임하지 않음
  • 최상위 타입 추론이 순환 의존성에서 예외를 던짐

Dart 2.19는 또한 이름 없는 라이브러리 지원을 도입했어요. 라이브러리 레벨 doc 주석과 어노테이션을 추가하는 데 쓰이는 library 지시문은 이제 이름 없이 쓸 수 있어요(그리고 그래야 해요).

/// A really great test library.
@TestOn('browser')
library;

Dart 2.18

2022년 8월 30일 릴리스 | Dart 2.18 공지

Dart 2.18은 타입 추론을 개선했어요. 이 변경은 제네릭 함수 호출의 인자 사이에 정보가 흐를 수 있게 해줘요. 2.18 이전에는 어떤 메서드에서 인자 타입을 지정하지 않으면 Dart가 오류를 보고했는데, 그 타입 오류는 잠재적 null 발생을 지적했어요. 2.18부터는 컴파일러가 호출의 다른 값들로부터 인자 타입을 추론하므로 인라인으로 지정할 필요가 없어졌어요.

또한 Dart 2.18은 Object를 확장하지 않는 믹스인 클래스 지원을 중단했어요.

이 기능들에 대해 더 알아보려면 다음을 참고해 주세요: 타입 인자 추론, 클래스에 기능 추가하기: 믹스인.

Dart 2.17

2022년 5월 11일 릴리스 | Dart 2.17 공지

Dart 2.17은 **향상된 enum(enhanced enums)**으로 enum 기능을 확장했어요. 향상된 enum은 enum 선언이 필드, 생성자, 메서드, getter 등을 포함한 멤버를 정의할 수 있게 해줘요.

Dart 2.17은 생성자에 super-initializer 매개변수 지원을 추가했어요. super 매개변수를 쓰면 non-redirecting 생성자의 super 호출에 각 매개변수를 일일이 전달하지 않아도 돼요. 대신 super 매개변수로 매개변수를 상위 클래스 생성자로 전달하면 되죠.

Dart 2.17은 이름 있는 인자에 대한 몇 가지 제한을 제거했어요. 이제 이름 있는 인자를 위치 인자와 자유롭게 섞을 수 있어요. 2.17부터는 다음 코드를 쓸 수 있어요.

void main() {
  test(skip: true, 'A test description', () {
    // Very long function body here...
  });
}

더 알아보려면 다음을 참고해 주세요: 향상된 enum, super 매개변수, 이름 있는 매개변수.

Dart 2.16

2022년 2월 3일 릴리스 | Dart 2.16 공지

Dart 2.16은 Dart 언어에 새 기능을 추가하지 않았어요. Dart 도구는 확장했죠.

Dart 2.15

2021년 12월 8일 릴리스 | Dart 2.15 공지

Dart 2.15는 함수 포인터, 즉 tear-off에 대한 지원을 개선했어요. 특히 생성자 tear-off가 이제 지원돼요.

Dart 2.14

2021년 9월 8일 릴리스 | Dart 2.14 공지

Dart 2.14는 **부호 없는 시프트(또는 삼중 시프트) 연산자 >>>**를 추가했어요. 이 새 연산자는 >>처럼 동작하지만, 항상 최상위 비트를 0으로 채워요.

이 연산자에 대해 더 알아보려면 비트 및 시프트 연산자를 참고해 주세요.

Dart 2.14는 타입 인자에 대한 몇 가지 제한을 제거했어요. 어노테이션에 타입 인자를 전달할 수 있고, 제네릭 함수 타입을 타입 인자로 사용할 수 있어요. 2.14부터는 다음 코드를 쓸 수 있어요.

@TypeHelper<int>(42, "The meaning")
late List<T Function<T>(T)> idFunctions;
var callback = [<T>(T value) => value];
late S Function<S extends T Function<T>(T)>(S) f;

Dart 2.13

2021년 5월 19일 릴리스 | Dart 2.13 공지

Dart 2.13은 타입 별칭(type alias, typedef) 지원을 확장했어요. 타입 별칭은 예전에는 함수 타입에만 동작했지만, 이제 어떤 타입에도 동작해요. 타입 별칭으로 만든 새 이름은 원래 타입을 쓸 수 있는 아무 곳에서나 쓸 수 있어요.

Dart 2.13은 Dart FFI의 struct 지원을 개선해, 인라인 배열과 packed struct를 지원하게 했어요.

Dart 2.12

2021년 3월 3일 릴리스 | Dart 2.12 공지

Dart 2.12는 sound null safety를 추가했어요. null safety를 선택하면 코드의 타입이 기본적으로 non-nullable이 되는데, 즉 명시적으로 허용하지 않는 한 변수에 null이 들어갈 수 없다는 뜻이에요. null safety를 쓰면 런타임의 null 역참조 오류가 편집 시점의 분석 오류로 바뀌어요.

Dart 2.12에서 Dart FFI는 베타에서 stable 채널로 졸업했어요.

Dart 2.10

2020년 10월 1일 릴리스 | Dart 2.10 공지

Dart 2.10은 Dart 언어에 새 기능을 추가하지 않았어요.

Dart 2.9

2020년 8월 5일 릴리스

Dart 2.9는 Dart 언어에 새 기능을 추가하지 않았어요.

Dart 2.8

2020년 5월 6일 릴리스 | Dart 2.8 공지

Dart 2.8은 Dart 언어에 기능을 추가하지 않았지만, null safety를 위해 nullable 관련 사용성과 성능을 개선하는 여러 예비 파괴적 변경을 포함했어요.

Dart 2.7

2019년 12월 11일 릴리스 | Dart 2.7 공지

Dart 2.7은 확장 메서드 지원을 추가했어요. 당신이 통제하지 않는 타입을 포함해 어떤 타입에도 기능을 추가할 수 있고, 일반 메서드 호출의 간결함과 자동 완성 경험을 그대로 누릴 수 있죠.

다음 예시는 dart:coreString 클래스를 parseInt() 메서드로 확장해요.

extension ParseNumbers on String {
  int parseInt() {
    return int.parse(this);
  }
}

void main() {
  int i = '42'.parseInt();
  print(i);
}

Dart 2.6

2019년 11월 5일 릴리스 | Dart 2.6 공지

Dart 2.6은 파괴적 변경(dart-lang/sdk#37985)을 도입했어요. NullFutureOr<T>의 하위 타입으로 작용하는 제약에서 이제 T의 해(solution)로 Null을 산출해요.

예를 들어 다음 코드는 이제 Null을 출력해요. Dart 2.6 이전에는 dynamic을 출력했죠. 익명 클로저 () {}Null 타입을 반환해요.

import 'dart:async';

void foo<T>(FutureOr<T> Function() f) { print(T); }

main() { foo(() {}); }

Dart 2.5

2019년 9월 10일 릴리스 | Dart 2.5 공지

Dart 2.5는 Dart 언어에 기능을 추가하지 않았지만, 새 핵심 라이브러리 **dart:ffi**로 Dart 코드에서 네이티브 C 코드를 호출하는 것을 지원했어요.

Dart 2.4

2019년 6월 27일 릴리스

Dart 2.4는 파괴적 변경(dart-lang/sdk#35097)을 도입했어요.

이제 Dart는 super-interface에서 사용되는 타입 변수의 공변성(covariance)을 강제해요. 예를 들어 이 릴리스 이전에는 Dart가 다음 코드를 받아들였지만, 이제는 거부해요.

class A<X> {};
class B<X> extends A<void Function(X)> {};

이제 비동기 및 제너레이터 함수에서 async를 식별자로 사용할 수 있어요.

Dart 2.3

2019년 5월 8일 릴리스 | Dart 2.3 공지

Dart 2.3은 선언형 UI 코드처럼 목록 조작을 수행하는 코드를 개선하기 위해 설계된 세 연산자를 추가했어요.

  • Spread 연산자: 한 목록의 요소를 다른 목록으로 풀어낼 수 있어요. 다음 예시에서 buildMainElements()가 반환한 목록을 children 인자로 전달되는 목록에 풀어 넣어요.
Widget build(BuildContext context) {
  return Column(children: [
    Header(),
    ...buildMainElements(),
    Footer(),
  ]);
}
  • Collection if 연산자: 요소를 조건부로 추가할 수 있어요. 다음 예시는 앱이 마지막 페이지를 표시하지 않는 한 FlatButton 요소를 추가해요.
Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    if (page != pages.last)
      FlatButton(child: Text('Next')),
  ]);
}
  • Collection for 연산자: 반복되는 요소를 만드는 것을 가능하게 해줘요. 다음 예시는 sections의 각 섹션에 HeadingAction 요소 하나를 추가해요.
Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    for (var section in sections)
      HeadingAction(section.heading),
  ]);
}

Dart 2.2

2019년 2월 26일 릴리스 | Dart 2.2 공지

Dart 2.2는 집합(set) 리터럴을 지원했어요.

const Set<String> currencies = {'EUR', 'USD', 'JPY'};

Dart 2.1

2018년 11월 15일 릴리스 | Dart 2.1 공지

Dart 2.1은 int-to-double 변환을 지원해, 개발자가 정수 리터럴로 double 값을 설정할 수 있게 했어요. 이 기능은 값이 개념상 정수일 때 4.0 같은 double 리터럴을 쓰도록 강제되던 불편을 없애줬어요.

다음 Flutter 코드에서 horizontalvertical은 타입이 double이에요.

padding: const EdgeInsets.symmetric(
  horizontal: 4,
  vertical: 8,
)

Dart 2.0

2018년 2월 22일 릴리스 | Dart 2.0 공지

Dart 2.0은 새로운 sound 타입 시스템을 구현했어요. Dart 2.0 이전에는 타입이 완전히 sound하지 않았고, Dart는 런타임 타입 검사에 크게 의존했어요. Dart 1.x 코드는 Dart 2로 마이그레이션해야 했죠.

언어 버전 관리 (Language versioning)

Dart 2.0 이후로 언어에 추가된 기능을 사용하려면, 그 기능을 지원하는 최초 릴리스를 SDK 제약의 하한으로 설정해야 해요. 페이지 시작 부분의 예시처럼, null safety(2.12 도입)를 쓰려면 pubspec.yamlenvironmentsdk: '>=2.12.0 <3.0.0'을 지정하면 돼요.

각 버전별 세부 변경 사항과 언어 버전 관리의 전체 이력은 Dart 공식 문서Breaking changes 페이지를 참고해 주세요.

더 알아보기 (Learn more)

  • Dart 공식 문서 - Dart language evolution 원문 살펴보기
  • 최근 지원 언어 버전의 구체적 세부 사항은 언어 문서나 언어 명세에서, SDK 변경의 전체 이력은 SDK 체인지로그에서 확인할 수 있어요.