Dart Internals, Version History and Effective Dart

50.1 How Dart Runs

Sound type system: runtime checks where needed (casts, covariant generics), plus AOT optimizations based on sound types (type-flow analysis, devirtualization, tree shaking).

Hot reload: the VM injects updated kernel code into the running isolate while preserving state (Flutter's signature feature).

Source (.dart) → Common Front End (CFE) → Kernel AST (.dill)
   ├── Dart VM: JIT (development, hot reload) / AOT compiler → native machine code (precompiled snapshot)
   ├── dart2js → optimized JavaScript (web production) / DDC → modular JS (web development)
   └── dart2wasm → WebAssembly with WasmGC
Runtime: per-isolate heaps, generational GC (scavenger for the young generation, mark-sweep/compact for the old generation), event loop, isolate groups

50.2 Version History Highlights

Initial stable release (optional typing, Dartium) Sound type system, strong mode, a focus on client/Flutter

Collection if/for/spread, extension methods Sound null safety (opt-in), FFI stable

Type aliases, constructor tear-offs, enhanced enums, super parameters, named args anywhere, Isolate.run

100% sound null safety, records, patterns, class modifiers (sealed/base/final/interface), switch expressions

Private final field promotion, Wasm progress Extension types, new JS interop (dart:js_interop)

Wasm compilation stable for Flutter web, macros preview (later cancelled), package:web 1.0 Digit separators, pub workspaces

Wildcard variables (_), the new "tall style" formatter Null-aware elements (?x in collection literals), cross-compilation for Linux, formatter improvements

Analyzer plugins, dot shorthands (3.10), native assets / build hooks, continued performance work (check the release notes for details)

50.3 Effective Dart: Key Guidelines

UpperCamelCase for types/extensions/enums, lowerCamelCase for members/variables/constants, lowercase_with_underscores for files/packages/import prefixes.

Use dart format. Prefer single quotes (per the lints). Use curly braces for all flow control (except single-line if without else).

✅ Use collection literals ([], {}), isEmpty/isNotEmpty, whereType, interpolation, ??/?., => for one-liners, initializing formals (this.x), and super parameters.

✅ Prefer final for locals/fields that don't change, and const where possible.

✅ Make classes immutable when practical. Override == and hashCode together.

✅ Use async/await over raw then chains. Always handle Future errors.

✅ Use sealed classes + switch for closed hierarchies, records for small aggregates, and extension types for type-safe wrappers.

❌ Avoid dynamic, late misuse, ! without justification, print in libraries (use logging), and catching without on clauses.

Name things clearly (verbs for side-effecting methods, nouns/adjectives for properties). Prefer named parameters for booleans and optional arguments.

Keep the public API small (lib/src for implementation, export a curated API). Use abstract interface class for contracts.

Design for testability: inject dependencies (clients, clocks, file systems).

Document every public API with ///. Start with a summary sentence. Use [references]. Include examples.