Skip to content

Introduction to Dart & Flutter

Dart is a client-optimised language developed by Google for building fast apps on any platform. It is the language behind Flutter, Google’s UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase.

  • AOT + JIT compilation: Dart compiles to native machine code ahead of time for production builds, and supports just-in-time compilation with hot reload during development.
  • Sound null safety: Since Dart 2.12, null safety is enforced at compile time, eliminating null reference errors at runtime.
  • Single-threaded with isolates: Dart uses a single-threaded event loop with isolates for concurrent programming, avoiding shared-state concurrency bugs.
  • Rich standard library: Collections, async/await, streams, and mathematical utilities are all built in.

Dart is the language; Flutter is the framework. You can use Dart without Flutter (server-side, CLI tools), but Flutter requires Dart. This site focuses on Dart the language; see the Flutter fundamentals section for UI development.

Dart is statically typed with type inference. The var keyword infers the type at compile time, while dynamic bypasses type checking entirely.

var name = 'Alice'; // inferred as String
String greeting = 'Hi'; // explicitly typed
dynamic value = 42; // type checked at runtime

Variables are non-nullable by default. Use ? to declare nullable types and ! to assert non-null (the null assertion operator).

String name = 'Alice'; // non-nullable
String? nickname = null; // nullable
print(nickname!.length); // null assertion (throws if null)

Dart provides Future and Stream for asynchronous operations, with async/await syntax for readable asynchronous code.

Future<String> fetchUser() async {
final response = await http.get(Uri.parse('https://api.example.com/user'));
return response.body;
}
  1. Using dynamic excessively: Dynamic defeats the purpose of Dart’s type system. Prefer explicit types or var inference.
  2. Forgetting null checks: Even with null safety, ! (null assertion) can throw at runtime. Use ?? (null coalescing) or ?. (null-aware access) instead.
  3. Mixing Future and Stream: await works with Future, but Stream requires await for or .listen(). Confusing them causes runtime errors.
void main() {
String? name = getName();
// Safe access with null-aware operator
print(name?.toUpperCase() ?? 'NO NAME');
}
String? getName() => null;
Future<void> main() async {
final data = await fetchData();
print('Received: $data');
}
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 1));
return 'Hello from async';
}

Dart is a modern, type-safe language designed for client-side development. Its combination of AOT/JIT compilation, null safety, and async/await makes it well-suited for building responsive applications with Flutter. Understanding the type system and null safety is essential before diving into Flutter widget development.

This section provides detailed coverage of advanced concepts, including full derivations, proofs, and extended examples.

Complete mathematical derivations and proofs are provided where appropriate. Each step is explained to ensure understanding of the underlying reasoning.

Advanced examples demonstrate the application of concepts to complex problems. These examples go beyond standard exam questions to develop deeper understanding.

This material connects to current research and advanced applications in the field. Understanding these connections provides context for the study material.

Ensure you have mastered the prerequisite material before attempting this advanced content.