Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Dart (3.13)  Module 19 – Staying current and preparing for interviews

What changed from Dart 3.0 to 3.13

Every Dart language change from 3.0 to 3.13 and the version it needs, a recorded upgrade of a Dart 2.19 package, and the outdated advice to check in tutorials.

  • Intermediate
  • 10 minutes
  • Examples run with dart 3.13.5 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 10 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • List the language change of each release from Dart 3.0 to 3.13 and the lower bound it needs
  • Predict the error a file gets when it uses a feature below the language version that introduced it
  • Move a Dart 2.19 package to the current language version with pub, dart fix and dart format
  • Identify outdated advice in older tutorials by testing it on the current SDK

Before you start

What you’ll learn · Before you start

What you will learn

  • List the language change of each release from Dart 3.0 to 3.13 and the lower bound it needs
  • Predict the error a file gets when it uses a feature below the language version that introduced it
  • Move a Dart 2.19 package to the current language version with pub, dart fix and dart format
  • Identify outdated advice in older tutorials by testing it on the current SDK

Before you start

On this page

A Dart 2.19 package with sdk: '>=2.19.0 <3.0.0' still compiles and runs on the 3.13.5 SDK, and dart analyze finds only six hints in it. Raise the lower bound to 3.0 and the same code gets two errors. Every Dart 3 release works like that: the SDK is new, but each package opts in to a language version, and the feature list you may use is decided by that number.

This lesson lists what each release from 3.0 to 3.13 added to the language, proves each feature by compiling it at its own version and one below, upgrades a small Dart 2.19 package step by step, and tests four things older tutorials still say. Every output was recorded with Dart 3.13.5.

Each language change needs a language version, set by the SDK constraint

The language version: The version of the Dart language a library is read with, written as major.minor, such as 3.13. A package's default is the lower bound of its SDK constraint. More in “What Dart is and where it runs” of a package is the lower bound of its SDK constraint: The environment sdk entry of pubspec.yaml, such as ^3.13.0: the Dart SDK versions a package works with. Its lower bound also sets the package's language version. More in “What Dart is and where it runs”. sdk: ^3.8.0 means that the code is compiled with the rules of language 3.8, and a feature that arrived in 3.10 is not available to it, however new the installed SDK is. An older constraint is not an error either. The Dart 3 migration guide explains that pub reads an upper bound of <3.0.0 as <4.0.0, so old packages keep resolving, and that is why the Dart 2.19 package above still ran. A single file can also set its own version with a first-line comment such as // @dart=3.8, which the next section uses.

The table gives every release from 3.0 to 3.13 with the lower bound that its language change needs:

Version Language change Lower bound
3.0 Records, patterns, switch expressions, class modifiers; null safety is mandatory ^3.0.0
3.2 Private final fields can be promoted by null checks and is tests ^3.2.0
3.3 Extension types; abstract getters promote like private final fields ^3.3.0
3.4 Sharper types for conditional, if-null and switch expressions ^3.4.0
3.6 Digit separators: 1_000_000 ^3.6.0
3.7 Wildcard variables, inference using bounds, and the tall style of dart format ^3.7.0
3.8 Null-aware elements: [?lunch] ^3.8.0
3.9 Promotion, reachability and definite assignment assume null safety ^3.9.0
3.10 Dot shorthands: .green for Color.green ^3.10.0
3.11 No language changes none
3.12 Private named parameters; primary constructors as an experiment ^3.12.0
3.13 Primary constructors; new or factory in place of the class name in other constructors; a tightened promotion rule ^3.13.0

Releases 3.1 and 3.5 changed no syntax. Walk the same list release by release, with what each change does:

Timeline · 12 events in order What each Dart 3 release changed in the language Walk the releases and note the lower bound your package needs for each feature.
  1. 3.0

    Records, patterns, switch expressions, class modifiers new syntax

    The release that made null safety mandatory also added records, pattern matching, switch expressions and class modifiers. A switch case is now a pattern, and a case needs no break.

  2. 3.2

    Private final field promotion flow analysis

    A private final field can be promoted by a null check or an is test, so if (_name != null) lets you use _name without a bang.

  3. 3.3

    Extension types new syntax

    An extension type wraps an existing type with a different static interface and is erased at run time, so it costs no wrapper object.

  4. 3.4

    Sharper conditional types type analysis

    Type analysis of conditional, if-null and switch expressions improved. A few cases changed their inferred types, which the changelog lists as breaking.

  5. 3.6

    Digit separators new syntax

    Underscores may group the digits of a number literal, as in 1_000_000. They do not change the value.

  6. 3.7

    Wildcard variables and the tall style new syntax

    A local variable or parameter named _ no longer binds a name, so it can be declared many times. Inference using bounds arrived, and dart format gained the tall style for packages at 3.7 or later.

  7. 3.8

    Null-aware elements new syntax

    A leading question mark in a collection literal, as in [?lunch], adds the value only when it is not null.

  8. 3.9

    Null safety assumed in analysis flow analysis

    Type promotion, reachability and definite assignment now assume sound null safety, so some code gets more accurate results and more dead-code warnings.

  9. 3.10

    Dot shorthands new syntax

    Where the context type is known, .green stands for Color.green, and .new for a constructor, so the type name is not repeated.

  10. 3.11

    No language changes tools only

    The release changed tools and libraries only, so no package needs a new lower bound for it.

  11. 3.12

    Private named parameters new syntax

    A named parameter can initialise a private field, as in Point({required this._x}), and callers still write x. Primary constructors arrived as an experiment.

  12. 3.13

    Primary constructors new syntax

    A class header can declare its constructor and fields, as in class Point(final int x, final int y);. Constructors in the class body may write new or factory instead of the class name, and a promotion rule was tightened to avoid unsound behaviour.

The timeline has 12 events, from 3.0 to 3.13.

Read the table as a ladder. A package that wants dot shorthands must set ^3.10.0 or higher, and by doing so it also gets every earlier rule, including the ones that broke old code, such as the removal of the colon before a default value in 3.0. That is why an upgrade goes one rung at a time.

Key idea

The SDK you install and the language version you compile with are two different numbers, and the second one comes from the lower bound of the SDK constraint in pubspec.yaml.

Checkpoint

Check: Language version and SDK constraint

  1. Question 1 of 2 Your project uses the 3.13.5 SDK and sdk: ^3.8.0 in pubspec.yaml. Which language version are the files compiled with?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 3.8, the lower bound of the constraint

    A dot shorthand from 3.10 would not be available to this package until its lower bound reaches 3.10.

  2. Question 2 of 2 A package says sdk: '>=2.19.0 <3.0.0'. What did the recorded run show on the 3.13.5 SDK?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It resolved and ran as before, with only hints from the analyzer

    New SDKs keep compiling old packages at their old language version. An upgrade is something you choose.

A feature fails one version below its own

The claim that a feature needs version X is easy to check. Each of eight small files starts with a comment that sets the version that introduced its feature, and the script runs the file as written and then again with that first line lowered by one version. The files use records (3.0), extension types (3.3), digit separators (3.6), wildcard variables (3.7), null-aware elements (3.8), dot shorthands (3.10), private named parameters (3.12) and primary constructors (3.13):

Eight features, each run at its version and one below Python · ladder_session.py
from session import files, run

# Eight features, each in a file whose first line sets the language version that introduced it. A second run lowers
# that line by one version.
files("ladder/records.dart=records.dart", "ladder/extension_type.dart=extension_type.dart", "ladder/digits.dart=digits.dart", "ladder/wildcard.dart=wildcard.dart", "ladder/null_aware_element.dart=null_aware_element.dart", "ladder/dot_shorthand.dart=dot_shorthand.dart", "ladder/private_named.dart=private_named.dart", "ladder/primary.dart=primary.dart", "ladder/ladder.sh=ladder.sh")
run(
    """
sh ladder.sh records 2.19
sh ladder.sh extension_type 3.2
sh ladder.sh digits 3.5
sh ladder.sh wildcard 3.6
sh ladder.sh null_aware_element 3.7
sh ladder.sh dot_shorthand 3.9
sh ladder.sh private_named 3.11
sh ladder.sh primary 3.12
""",
)

Output

$ sh ladder.sh records 2.19
records as written: x=1.5 y=2.5
records at 2.19: lower.dart:2:1: Error: This requires the experimental 'records' language feature to be enabled.
$ sh ladder.sh extension_type 3.2
extension_type as written: 42m
extension_type at 3.2: lower.dart:2:11: Error: The 'inline-class' language feature is disabled for this library.
$ sh ladder.sh digits 3.5
digits as written: 1002500
digits at 3.5: lower.dart:2:22: Error: This requires the experimental 'digit-separators' language feature to be enabled.
$ sh ladder.sh wildcard 3.6
wildcard as written: xxx
wildcard at 3.6: lower.dart:4:7: Error: '_' is already declared in this scope.
$ sh ladder.sh null_aware_element 3.7
null_aware_element as written: [tea, water]
null_aware_element at 3.7: lower.dart:5:10: Error: This requires the experimental 'null-aware-elements' language feature to be enabled.
$ sh ladder.sh dot_shorthand 3.9
dot_shorthand as written: Color.green
dot_shorthand at 3.9: lower.dart:5:13: Error: This requires the experimental 'dot-shorthands' language feature to be enabled.
$ sh ladder.sh private_named 3.11
private_named as written: Point(1, 2)
private_named at 3.11: lower.dart:4:24: Error: The 'private-named-parameters' language feature is disabled for this library.
$ sh ladder.sh primary 3.12
primary as written: 7
primary at 3.12: lower.dart:2:12: Error: The 'primary-constructors' language feature is disabled for this library.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 ladder_session.py

Every file ran as written and failed one version below, and the message is worth reading. For records, digit separators, null-aware elements and dot shorthands it said that the feature needs an experimental flag, which is how the compiler names a feature that is not yet part of the language at that version. For extension types, private named parameters and primary constructors it said that the language feature is disabled for this library; the next line of each message, cut from the run above, asks for a language version of 3.3, 3.12 or 3.13 or higher. The wildcard file failed in a different way: at 3.6 the second var _ was a redeclaration of the first. So when a teammate on an older constraint sees “language feature is disabled”, the fix is in the lower bound, not in the code.

The first-line comment is a test tool

// @dart=3.8 applies to one file and is useful for experiments like this one. A real package sets the version once, in pubspec.yaml, so that all its files agree.

Checkpoint

Check: A feature fails below its own version

  1. One question A teammate on sdk: ^3.2.0 writes an extension type and the compiler says the language feature is disabled for this library. What is the fix?

    Choose one answer.

    Show the answer: One question

    Answer: Raise the lower bound to 3.3 or higher and run dart pub get

    When a feature is disabled for a library, look at the language version first.

Upgrading a Dart 2 package one step at a time

A small shop package is written the way Dart 2.19 code was: a plain class used as a mixin, a colon before a default value, new everywhere, this. in front of members, and three statements laid out in the old style. The session moves it from 2.19 to 3.13 in two steps. The first step raises the lower bound to 3.0, the second to 3.13:

The shop package before the upgrade

upgrade/pubspec.yaml

name: shop
description: A small shop written in the style of Dart 2.19.
version: 1.0.0
publish_to: none

environment:
  sdk: '>=2.19.0 <3.0.0'

upgrade/analysis_options.yaml

linter:
  rules:
    - unnecessary_new
    - unnecessary_const
    - prefer_collection_literals
    - prefer_final_fields
    - unnecessary_this

lib/shop.dart · upgrade/lib/shop.dart

class Logger {
  void log(String message) => print('log: $message');
}

class Shop with Logger {
  final items = new Map<String, int>();
  final int limit;

  Shop({this.limit : 3});

  void add(String name, int quantity) {
    if (this.items.length >= limit) {
      log('shop is full, skipping $name');
      return;
    }
    this.items[name] = quantity;
  }

  String describe(Object? value) {
    if (value is List) {
      return 'a list of ${value.length}';
    } else if (value is Map) {
      return 'a map of ${value.length}';
    } else if (value == null) {
      return 'nothing';
    }
    return 'something else';
  }
}

lib/report.dart · upgrade/lib/report.dart

String summary(Map<String, int> stock, int limit, String shop) {
  final label = stock.length > limit ? 'overstocked at $shop with ${stock.length} lines' : stock.isEmpty ? 'empty at $shop' : 'normal at $shop';
  final total = stock.values.fold<int>(0, (sum, quantity) => sum + quantity) + stock.length * 2 + limit * 3 + shop.length;
  return label + ', ' + total.toString() + ' units counted';
}

List<String> longNames(List<String> names) {
  final shouted = ['asha', 'ravi', 'meena'].map((name) => name.toUpperCase()).where((name) => name.length > 3).toList();
  return shouted;
}

bin/main.dart · upgrade/entry/main.dart

import 'package:shop/report.dart';
import 'package:shop/shop.dart';

void main() {
  final shop = new Shop(limit: 2);
  shop.add('tea', 4);
  shop.add('rice', 10);
  shop.add('salt', 1);
  print(shop.describe(shop.items));
  print(shop.describe([1, 2, 3]));
  print(shop.describe(null));
  print(summary(shop.items, 1, 'Pune'));
  print(longNames(['x']));
}
From 2.19 to 3.0 to 3.13: analyze, fix, format Python · upgrade_session.py
from session import files, run

# A package written for Dart 2.19, moved up in steps: first as it is, then to 3.0, then to 3.13.
files("upgrade/pubspec.yaml=pubspec.yaml", "upgrade/analysis_options.yaml=analysis_options.yaml", "upgrade/lib=lib", "upgrade/entry=bin")
run(
    """
dart pub get --offline | tail -1
dart run bin/main.dart
dart analyze | tail -n +3 | cut -c1-110
# step 1: raise the lower bound to 3.0, then pub get so that the language version follows
sed "s/sdk: '>=2.19.0 <3.0.0'/sdk: ^3.0.0/" pubspec.yaml > p.tmp && mv p.tmp pubspec.yaml
dart analyze | tail -1
dart pub get --offline | tail -1
dart analyze | grep error | cut -c1-120
dart fix --apply | tail -1
sed 's/^class Logger/mixin Logger/' lib/shop.dart > s.tmp && mv s.tmp lib/shop.dart
dart analyze | tail -1
dart run bin/main.dart > run.txt
head -2 run.txt
# step 2: raise it to 3.13 and format with the style that goes with it
dart format lib | tail -1
cp -R lib lib-before
sed "s/sdk: ^3.0.0/sdk: ^3.13.0/" pubspec.yaml > p.tmp && mv p.tmp pubspec.yaml
dart pub get --offline | tail -1
dart format lib | tail -1
diff -u lib-before/report.dart lib/report.dart | tail -n +3
""",
    pub=True,
)

Output

$ dart pub get --offline | tail -1
Got dependencies!
$ dart run bin/main.dart
log: shop is full, skipping salt
a map of 2
a list of 3
nothing
overstocked at Pune with 2 lines, 25 units counted
[ASHA, RAVI, MEENA]
$ dart analyze | tail -n +3 | cut -c1-110
   info - bin/main.dart:5:16 - Unnecessary 'new' keyword. Try removing the 'new' keyword. - unnecessary_new
   info - lib/shop.dart:6:17 - Unnecessary 'new' keyword. Try removing the 'new' keyword. - unnecessary_new
   info - lib/shop.dart:6:17 - Unnecessary constructor invocation. Try using a collection literal. - prefer_co
   info - lib/shop.dart:9:20 - Using a colon as the separator before a default value is deprecated and will no
   info - lib/shop.dart:12:9 - Unnecessary 'this.' qualifier. Try removing 'this.'. - unnecessary_this
   info - lib/shop.dart:16:5 - Unnecessary 'this.' qualifier. Try removing 'this.'. - unnecessary_this

6 issues found.
# step 1: raise the lower bound to 3.0, then pub get so that the language version follows
$ sed "s/sdk: '>=2.19.0 <3.0.0'/sdk: ^3.0.0/" pubspec.yaml > p.tmp && mv p.tmp pubspec.yaml
$ dart analyze | tail -1
6 issues found.
$ dart pub get --offline | tail -1
Got dependencies!
$ dart analyze | grep error | cut -c1-120
  error - lib/shop.dart:5:17 - The class 'Logger' can't be used as a mixin because it's neither a mixin class nor a mixi
  error - lib/shop.dart:9:20 - Using a colon as the separator before a default value is no longer supported. Try replaci
$ dart fix --apply | tail -1
5 fixes made in 2 files.
$ sed 's/^class Logger/mixin Logger/' lib/shop.dart > s.tmp && mv s.tmp lib/shop.dart
$ dart analyze | tail -1
No issues found!
$ dart run bin/main.dart > run.txt
$ head -2 run.txt
log: shop is full, skipping salt
a map of 2
# step 2: raise it to 3.13 and format with the style that goes with it
$ dart format lib | tail -1
Formatted 2 files (1 changed) in … seconds.
$ cp -R lib lib-before
$ sed "s/sdk: ^3.0.0/sdk: ^3.13.0/" pubspec.yaml > p.tmp && mv p.tmp pubspec.yaml
$ dart pub get --offline | tail -1
Got dependencies!
$ dart format lib | tail -1
Formatted 2 files (1 changed) in … seconds.
$ diff -u lib-before/report.dart lib/report.dart | tail -n +3
@@ -2,9 +2,10 @@
   final label = stock.length > limit
       ? 'overstocked at $shop with ${stock.length} lines'
       : stock.isEmpty
-          ? 'empty at $shop'
-          : 'normal at $shop';
-  final total = stock.values.fold<int>(0, (sum, quantity) => sum + quantity) +
+      ? 'empty at $shop'
+      : 'normal at $shop';
+  final total =
+      stock.values.fold<int>(0, (sum, quantity) => sum + quantity) +
       stock.length * 2 +
       limit * 3 +
       shop.length;
@@ -12,9 +13,10 @@
 }

 List<String> longNames(List<String> names) {
-  final shouted = ['asha', 'ravi', 'meena']
-      .map((name) => name.toUpperCase())
-      .where((name) => name.length > 3)
-      .toList();
+  final shouted = [
+    'asha',
+    'ravi',
+    'meena',
+  ].map((name) => name.toUpperCase()).where((name) => name.length > 3).toList();
   return shouted;
 }

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 upgrade_session.py

Follow the order of the run in the next figure:

Interactive · stage by stage Moving a Dart 2.19 package to 3.13 Step through the order of the upgrade and what each step changes in the package.
Moving a Dart 2.19 package to 3.13, step 6 of 6. Showing As it is, Lower bound 3.0, dart fix --apply, Changes by hand, Lower bound 3.13, dart format. In focus: dart format.As it issdk >=2.19.0 <3.0.0Lower bound 3.0then dart pub getdart fix --applymechanical changesChanges by handwhat no fix coversLower bound 3.13then dart pub getdart formatthe tall style

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The old package still runs. The SDK reads the upper bound <3.0.0 as <4.0.0, and the language version stays at 2.19, so the code ran as before and the analyzer only reported deprecations.
  2. Raise the lower bound to 3.0. The language version follows the lower bound, but only once dart pub get rewrites package_config.json; straight after the edit the analyzer still reported the 6 issues it found at 2.19. After pub get it reports two errors, the colon it had flagged as deprecated and a plain class used as a mixin.
  3. Mechanical edits with dart fix. dart fix --apply made 5 fixes in 2 files, removing new, the this. qualifiers and a constructor call that a literal replaces, and replacing a colon default value with an equals sign.
  4. Fix what no tool covers. Logger was a plain class used as a mixin, which Dart 3 refuses. Declaring it with mixin was a one-word edit by hand, and the analyzer then reported no issues.
  5. Raise the lower bound to 3.13. With the bound at 3.13 and a fresh pub get, new language features are available in the package, and the formatter looks at the language version of each file.
  6. Format with the matching style. Language 3.7 or later gets the tall style. Three statements in report.dart changed shape, and no other file changed, so a style change makes a small diff of its own.

Three points from the run. The package ran and passed analysis with only hints before anything changed, so an upgrade is a decision, not an emergency. Straight after the bound moved to 3.0, dart analyze still reported 6 issues, the count it gave at 2.19, because the language version is read from the package configuration that dart pub get writes, not from pubspec.yaml directly. Only after pub get ran again did the analyzer report two errors: Logger cannot be used as a mixin, and the colon before the default value is no longer supported. dart fix --apply then made five fixes in two files, which covered the colon and the style hints but not the mixin: one word, mixin Logger, by hand. Finally, after the bound moved to 3.13, dart format reshaped three statements of report.dart into the tall style: The code style that dart format applies to files at language version 3.7 or later. It adds and removes trailing commas itself, so long calls and chains break into short lines., and no other file changed. Commit the style change on its own, so that the diff of the real upgrade stays small.

Climb in steps

Move to 3.0 first and get a clean dart analyze, then to the current version. Each step has few errors, and each can be merged alone.

Checkpoint

Check: Upgrading a Dart 2 package in steps

  1. Question 1 of 2 You change sdk: to ^3.0.0 in pubspec.yaml and run dart analyze straight away. The old errors do not appear. Why?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The language version is read from the package configuration, which dart pub get rewrites

    After changing the SDK constraint, run dart pub get before you trust any result.

  2. Question 2 of 2 After dart fix --apply made 5 fixes in the shop package, one error was left. What was it, and how was it fixed?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Logger was a class used as a mixin, and declaring it with mixin fixed it by hand

    Automatic fixes cover the mechanical changes. Anything that changes meaning is yours to decide.

Outdated advice to test before you trust it

Tutorials written for Dart 2 are still easy to find, and some of what they say stopped being true. A quick run on the current SDK settles many of the claims. This session checks four of them: that Dart has method overloading, that a switch case needs break, that a stream can be listened to only once unless it is a broadcast stream, and that dart migrate upgrades a package to null safety:

Four claims from older tutorials, checked on 3.13 Python · advice_session.py
from session import files, run

# Four things older tutorials say, checked against the Dart 3.13 SDK. dart migrate writes its reply to a file, so its
# status is its own and not that of a pipe that head may close early.
files("advice/overload.dart=overload.dart", "advice/switch_cases.dart=switch_cases.dart", "advice/streams.dart=streams.dart")
run(
    """
dart run overload.dart 2>&1 | head -2
dart run switch_cases.dart
dart run streams.dart
!dart migrate > migrate.txt 2>&1
head -1 migrate.txt
""",
)

Output

$ dart run overload.dart 2>&1 | head -2
overload.dart:3:10: Error: 'greet' is already declared in this scope.
  String greet(String name, String title) => 'Hello, $title $name';
$ dart run switch_cases.dart
one
two
still two
other
$ dart run streams.dart
first listener: [1, 2, 3]
second listener: [1, 2, 3]
$ dart migrate > migrate.txt 2>&1
[exit status 64]
$ head -1 migrate.txt
Could not find a command named "migrate".

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 advice_session.py

Dart never had overloading: the second greet is an error because the name is already declared, and optional or named parameters are the Dart way. A switch case in Dart 3 ends by itself, and several statements in one case run without a break. The stream claim is only half true: a stream built by Stream.fromIterable was listened to twice and gave the same list both times, so do not write that every stream that is not a broadcast stream can be listened to only once. Finally dart migrate is gone, because null-safety migration is over and Dart 3 is sound null safety only.

Other lines to be careful with: dart:html and dart:js are deprecated, package:js is discontinued, and dart2wasm refuses all three while dart2js still compiles them, as the lesson on web interop shows. Macros are not coming: the Dart team’s post on the subject says that it stopped its work on them. Experimental syntax, such as the primary constructors that 3.12 offered as a preview, needs an experiment flag: A command-line option such as --enable-experiment=name that turns on a language feature before it is released. Code that needs a flag can change or break between SDK releases. like dart run --enable-experiment=primary-constructors. The experiment-flags documentation warns against experiments in production code, since they can change or disappear without notice. Keep them out of published packages.

Checkpoint

Check: Testing advice from older tutorials

  1. Question 1 of 2 A tutorial says every switch case needs break. What did the recorded run of switch_cases.dart print for code 2?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: two and still two, with no break in the case

    Since Dart 3.0 a switch case does not fall through, and break is optional.

  2. Question 2 of 2 A document says that every stream that is not a broadcast stream can be listened to only once. What did the stream run show?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Stream.fromIterable was read twice and gave the same list both times, so the claim is wrong in general

    Test a sweeping claim with one run. A stream that can create its events again for each listener can be listened to repeatedly, while a stream built from a controller or a socket cannot.

Practise: bring a package up to date

Take any small package you have, or copy the shop package, and move it up in steps. Run each command and read what it says before you go on.

  1. Run dart pub get, dart analyze and the program with the constraint exactly as it is, and write down the hints.
  2. Raise the lower bound to ^3.0.0, run dart pub get, and list every error the analyzer reports.
  3. Run dart fix --dry-run to see what it proposes, then dart fix --apply, then fix the remaining errors by hand.
  4. Adopt a record or a pattern in one place where a function returns two values or tests a type, and keep the tests green.
  5. Raise the bound to your SDK’s version, run dart pub get, then dart format ., and commit the formatting alone.
  6. Look at dart pub outdated and move one dependency at a time to its latest major version.

Practice that adapts to you

Practise this lesson

10 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 10 Which constraint gives a package access to dot shorthands?

    Choose one answer.

    Show the answer: Question 1 of 10

    Answer: sdk: ^3.10.0

    A feature is available from the version that introduced it, up.

  2. Question 2 of 10 Which release in the range 3.0 to 3.13 had no language changes?

    Choose one answer.

    Show the answer: Question 2 of 10

    Answer: 3.11

    A release without language changes still brings tools and library changes, but it never raises a package's bound.

  3. Question 3 of 10 Put these features in the order of the release that introduced them, earliest first.

    Give each item its position, from 1 (first).

    Show the answer: Question 3 of 10

    Answer:

    1. Records and patterns
    2. Extension types
    3. Wildcard variables
    4. Null-aware elements
    5. Dot shorthands
    6. Primary constructors

    They arrived in 3.0, 3.3, 3.7, 3.8, 3.10 and 3.13, which is also the order in which an upgrade climbs.

  4. Question 4 of 10 The compiler says that digit separators need the experimental feature 'digit-separators' on a file at 3.5. What does that mean?

    Choose one answer.

    Show the answer: Question 4 of 10

    Answer: The feature is not part of the language at version 3.5, and the lower bound has to move

    An experimental flag in an error can point to a feature that has since shipped. Compare the version.

  5. Question 5 of 10 The wildcard file failed at 3.6 in a different way from the others. What did the error say?

    Choose one answer.

    Show the answer: Question 5 of 10

    Answer: That _ is already declared in this scope, because before 3.7 a variable named _ was an ordinary name

    A change in the meaning of existing syntax shows up as a different error from a new keyword.

  6. Question 6 of 10 Put the steps of the shop upgrade in the order the session ran them.

    Give each item its position, from 1 (first).

    Show the answer: Question 6 of 10

    Answer:

    1. Run the package as it is and note the hints
    2. Raise the lower bound to 3.0 and run dart pub get
    3. Run dart fix --apply
    4. Declare Logger with mixin by hand
    5. Raise the lower bound to 3.13 and run dart pub get
    6. Run dart format and review the diff

    Each step leaves the package working, so each one can be merged on its own.

  7. Question 7 of 10 After the bound moved to 3.13, dart format changed three statements in report.dart and no other file. Why is a separate commit for it a good idea?

    Choose one answer.

    Show the answer: Question 7 of 10

    Answer: The style change touches layout only, and keeping it apart leaves the diff of the real upgrade small and reviewable

    Separate mechanical changes from meaningful ones so that review is quick.

  8. Question 8 of 10 What did the compiler say about two methods named greet with different parameters?

    Choose one answer.

    Show the answer: Question 8 of 10

    Answer: That greet is already declared in this scope, because Dart has no overloading

    A tutorial that shows overloading in Dart is describing another language.

  9. Question 9 of 10 What does dart migrate do on the 3.13.5 SDK?

    Choose one answer.

    Show the answer: Question 9 of 10

    Answer: Nothing, because the command no longer exists

    Null-safety migration ended when Dart 3 made sound null safety the only mode.

  10. Question 10 of 10 A library uses primary constructors with --enable-experiment=primary-constructors in its published example. Why is that a risk for people who copy it?

    Choose one answer.

    Show the answer: Question 10 of 10

    Answer: Experiments can change or be removed without notice, so code that needs a flag can break between releases

    Keep experiments in your own scratch code until the language version that ships them is the one you can require.

Interview questions

Warm-up (fresher to 2-5 years): Which Dart version introduced records and patterns, and what does a package have to do to use them?

Dart 3.0 introduced both, along with switch expressions and class modifiers. A package uses them by raising the lower bound of its SDK constraint to 3.0, as in sdk: ^3.0.0, and running dart pub get so that the language version follows. Installing a newer SDK is not enough, because the language version of a package comes from that lower bound. A file in a package that is still at language 2.19 gets an error that names the feature, such as records, as one that needs an experimental flag. Raising the bound also brings every rule that arrived with 3.0, including the removal of the colon before a default value and the rule that only a class declared with mixin or mixin class can be used as a mixin, so run the analyzer right after the change.

Two questions from the module’s bank go further, into planning a real upgrade and into checking what older documents say:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A package with 80 files and sdk '>=2.19.0 <3.0.0' must reach the current language version within a week. Give the order of the steps, say what runs automatically and what needs a person, and how you know each step is safe to merge.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    You inherit a wiki that says switch needs break, dart migrate upgrades a package to null safety, and macros arrive soon. How do you check each claim against the current SDK, and what do you write in its place?

    Model answer, Pro. First step and follow-ups

Flashcards · 7 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Where does a package's language version come from?

    From the lower bound of its SDK constraint in pubspec.yaml, read through the package configuration that dart pub get writes. A newer SDK compiles an old package at its old language version.

  2. In which versions did records and patterns, extension types, digit separators and wildcard variables arrive?

    Records and patterns in 3.0, extension types in 3.3, digit separators in 3.6 and wildcard variables in 3.7.

  3. In which versions did null-aware elements, dot shorthands, private named parameters and primary constructors arrive?

    Null-aware elements in 3.8, dot shorthands in 3.10, private named parameters in 3.12 and primary constructors in 3.13.

  4. What happens when code uses a feature below the language version that introduced it?

    It fails with a message that names the feature, and the cure is raising the lower bound of the SDK constraint. A // @dart=x.y comment changes the version of one file, which is useful for experiments.

  5. How do you upgrade a Dart 2.19 package?

    In steps: raise the lower bound to 3.0, run pub get, let dart fix --apply do the mechanical work and fix the rest by hand, then raise it to the current version and format in a commit of its own.

  6. Which old tutorial claims does the current SDK disprove?

    Overloading never existed, break is not needed at the end of a switch case, Stream.fromIterable can be listened to twice, and dart migrate is gone.

  7. Why do language experiments stay out of production code?

    They sit behind flags and can change without notice, so they stay out of production code and published packages.

Key takeaways

  • The language version of a package is the lower bound of its SDK constraint, read through the package configuration that dart pub get writes, and a new SDK compiles old packages at their old version.
  • Each release added at most a few language features: records and patterns in 3.0, extension types in 3.3, digit separators in 3.6, wildcard variables in 3.7, null-aware elements in 3.8, dot shorthands in 3.10, private named parameters in 3.12 and primary constructors in 3.13.
  • A feature used below its version fails with a message that names it, and the cure is the lower bound.
  • Upgrade in steps: raise to 3.0, run pub get, let dart fix --apply do the mechanical work, fix the rest by hand, then raise to the current version and format in a commit of its own.
  • Test a claim from an old tutorial on the current SDK before you rely on it: overloading never existed, break is not needed, Stream.fromIterable can be listened to twice, and dart migrate is gone.
  • Experiments sit behind flags and can change without notice, so they stay out of production code and published packages.

Terms in this lesson

experiment flag
A command-line option such as --enable-experiment=name that turns on a language feature before it is released. Code that needs a flag can change or break between SDK releases.
tall style
The code style that dart format applies to files at language version 3.7 or later. It adds and removes trailing commas itself, so long calls and chains break into short lines.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.