Skip to content

Dart Practice (Fundamentals)

Intuition

Learning through practice: Practice problems are like training drills, they help you apply knowledge and identify areas that need more study.

Why it matters: Regular practice builds confidence and reveals patterns in how concepts are tested. Each problem reinforces key programming concepts.

The key insight: Making mistakes during practice is valuable, each error points to a concept that needs clarification.

Dart — Interactive Practice

10 auto-graded practice problems covering core Dart concepts. Select an answer, submit, and review the explanation.


Null Safety and Types

Q1. What happens when you declare String name; in a Dart file with null safety enabled?

A. Compilation error: non-nullable variable must be initialized B. name is set to null C. name is set to an empty string D. It compiles successfully’,

<details> <summary>Show answer, A</summary>

Answer: A, With null safety enabled, all non-nullable variables must be initialized at declaration. String name; without an initializer or late keyword produces a compilation error. To fix: initialize it (String name = 'Alice';), make it nullable (String? name;), or defer with late (late String name;).

Q2. What is the type of List\&lt;int&gt;? numbers = [1, 2, 3];?

A. The variable is of type List\&lt;int&gt;? and currently holds a non-null List\&lt;int&gt; B. It is of type List\&lt;int&gt; (the ? is ignored) C. Compilation error: cannot assign List&lt;int> to List&lt;int>? D. It is of type dynamic’,

<details> <summary>Show answer, A</summary>

Answer: A, List&lt;int>? is a nullable list type. The variable numbers can hold either a List\&lt;int&gt; or null. The initializer [1, 2, 3] is a valid List\&lt;int&gt;so it compiles. The ? does not make the list elements nullable — only the list reference itself can be null.

</details>

Q3. Which Dart collection type guarantees uniqueness of elements?

A. List B. Map C. Queue D. Set

<details> <summary>Show answer, D</summary>

Answer: D, A Set is an unordered collection of unique elements backed by a hash table. Adding a duplicate element is silently ignored: \{'a', 'b', 'a'\} becomes \{'a', 'b'\}. Use Set for fast O(1) membership checks (contains), deduplication (Set.from(list).toList()), and mathematical set operations (union, intersection, difference).


Async and Streams

Q4. What does Stream.fromIterable([1, 2, 3]).listen((value) => print(value * 2)) output?

A. 246 B. 2, 4, 6 (in order, one per event) C. 6 D. Compilation error

<details> <summary>Show answer, B</summary>

Answer: B, Stream.fromIterable creates a single-subscription stream that emits each element of the iterable as a separate event. The listener multiplies each value by 2: 12=2, 22=4, 3*2=6. Events are delivered asynchronously but in order for synchronous iterables. After emitting all three, the stream completes.

Q5. Given Future\&lt;String&gt; fetchName() async \{ await Future.delayed(Duration(seconds: 1)); return 'Alice'; \}, what is the type of var result = fetchName();?

A. String B. dynamic C. void D. Future\&lt;String&gt;

Answer: D, Calling an async function without await returns the Future immediately without waiting for it to complete. var result = fetchName(); gives result the type Future\&lt;String&gt;not String. To get the String value, you must await it: var result = await fetchName(); which yields type String.


Dart 3 Features

Q6. Given sealed class Result \{\} class Success extends Result \{\} class Failure extends Result \{\}, which switch expression is exhaustive without a default case?

A. switch (r) { case Success(): … case Failure(): … } B. switch (r) { case Success(): … } C. switch (r) { default: … } D. switch (r) { case Result(): … }’,

<details> <summary>Show answer, A</summary>

Answer: A, Sealed classes restrict subtypes to a known finite set. The compiler knows Result has exactly two subtypes: Success and Failure. A switch covering both is exhaustive — no default needed. This is the primary benefit of sealed classes: safe, compile-time-verified exhaustive pattern matching.

Q7. In Dart 3 records, how do you access the first positional field of var record = ('Alice', 30);?

A. record[0] B. record.$1 C. record.first D. record.0

<details> <summary>Show answer, B</summary>

Answer: B, Record positional fields are accessed via $1, $2, $3etc. (1-indexed). Named fields use dot notation: var (name, age) = record; for destructuring, or record.$1 returns ‘Alice’ and record.$2 returns 30. The $ prefix distinguishes record fields from regular properties.


OOP and Extensions

Q8. Given mixin Walker \{ void walk() => print('walking'); \} and class Person extends Animal with Walker \{\}, what is the result of calling walk() on a Person instance?

A. “Prints ‘walking’ — Walker’s method is mixed into Person”, ‘Throws NoSuchMethodError’, “Calls Animal’s walk method instead”, ‘Compilation error: Walker cannot be used with Person’,

<details> <summary>Show answer, A</summary>

Answer: A, Mixins inject their method implementations into the class that uses them. Person gains the walk() method from Walker. If Person also defines walk()its own method takes precedence (override). If Animal defines walk() and Walker also defines it, the mixin’s linearization order determines which wins — mixins applied later have higher priority.

Q1. What happens when you declare String name; in a Dart file with null safety enabled?

A. Compilation error: non-nullable variable must be initialized B. name is set to null C. name is set to an empty string D. It compiles successfully’,

Answer: A

  • With null safety enabled, all non-nullable variables must be initialized at declaration. String name; without an initializer or late keyword produces a compilation error. To fix: initialize it (String name = 'Alice';), make it nullable (String? name;), or defer with late (late String name;). Difficulty: hard

Q2. What is the type of List&lt;int&gt;? numbers = [1, 2, 3];?

A. The variable is of type List&lt;int&gt;? and currently holds a non-null List&lt;int&gt; B. It is of type List&lt;int&gt; (the ? is ignored) C. Compilation error: cannot assign List<int> to List<int>? D. It is of type dynamic’,

Answer: A

  • List&lt;int&gt;? is a nullable list type. The variable numbers can hold either a List&lt;int&gt; or null. The initializer [1, 2, 3] is a valid List&lt;int&gt;, so it compiles. The ? does not make the list elements nullable — only the list reference itself can be null. Difficulty: medium

Q3. Which Dart collection type guarantees uniqueness of elements?

A. List B. Map C. Queue D. Set

Answer: D

  • A Set is an unordered collection of unique elements backed by a hash table. Adding a duplicate element is silently ignored: \{'a', 'b', 'a'\} becomes \{'a', 'b'\}. Use Set for fast O(1) membership checks (contains), deduplication (Set.from(list).toList()), and mathematical set operations (union, intersection, difference). Difficulty: hard

Q4. What does Stream.fromIterable([1, 2, 3]).listen((value) => print(value * 2)) output?

A. 246 B. 2, 4, 6 (in order, one per event) C. 6 D. Compilation error

Answer: B

  • Stream.fromIterable creates a single-subscription stream that emits each element of the iterable as a separate event. The listener multiplies each value by 2: 12=2, 22=4, 3*2=6. Events are delivered asynchronously but in order for synchronous iterables. After emitting all three, the stream completes. Difficulty: hard

Q5. Given Future&lt;String&gt; fetchName() async \{ await Future.delayed(Duration(seconds: 1)); return 'Alice'; \}, what is the type of var result = fetchName();?

A. String B. dynamic C. void D. Future&lt;String&gt;

Answer: D

  • Calling an async function without await returns the Future immediately without waiting for it to complete. var result = fetchName(); gives result the type Future&lt;String&gt;, not String. To get the String value, you must await it: var result = await fetchName(); which yields type String. Difficulty: medium

Q6. Given sealed class Result \{\} class Success extends Result \{\} class Failure extends Result \{\}, which switch expression is exhaustive without a default case?

A. switch (r) { case Success(): … case Failure(): … }

Answer: A

  • Sealed classes restrict subtypes to a known finite set. The compiler knows Result has exactly two subtypes: Success and Failure. A switch covering both is exhaustive — no default needed. This is the primary benefit of sealed classes: safe, compile-time-verified exhaustive pattern matching. Difficulty: medium

Q7. In Dart 3 records, how do you access the first positional field of var record = ('Alice', 30);?

A. record[0] B. record.$1 C. record.first D. record.0

Answer: B

  • Record positional fields are accessed via $1, $2, $3, etc. (1-indexed). Named fields use dot notation: var (name, age) = record; for destructuring, or record.$1 returns ‘Alice’ and record.$2 returns 30. The $ prefix distinguishes record fields from regular properties. Difficulty: medium

Q8. During Dart null safety migration, which approach does the Dart team recommend as the primary strategy?

A. Analyze existing code, add ? where nulls are intended, remove unnecessary !, and use late for lazily initialized fields B. Set the entire project to // @dart=2.9 and avoid migration C. Replace all nullable types with dynamic D. Rewrite the project from scratch with null safety from day one’,

Answer: A

  • The recommended migration flow: 1) Enable null safety incrementally with // @dart=2.12 or per-package. 2) Run the migration tool (dart fix --apply). 3) Review: add ? where nulls are intentional, replace ! with proper null checks, use late for fields initialized in initState or constructors. 4) Run analysis (dart analyze) to find remaining issues. 5) Remove ! operators one by one — each removed operator is a safety improvement. Difficulty: hard

Q9. In a Flutter StatefulWidget, which lifecycle method should you use to initialize data that depends on BuildContext or to subscribe to a stream?

A. initState B. the constructor C. didChangeDependencies D. build

Answer: A

  • initState() is called once when the State object is created, before build(). It is the correct place to initialize data, subscribe to streams, and set up controllers that depend on this.context. Do NOT call BuildContext-dependent methods (like Theme.of(context)) in initState — use didChangeDependencies for those. Clean up subscriptions in dispose(). Difficulty: hard