skip to content

Everyday Syntax

The language's building blocks: var, final and const, numbers and strings, cascades, loops, parameter lists and try/catch. Interviewers open with final versus const to test precision.

part ofDartoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

In Dart, how does a variable typed dynamic differ from one typed Object?, and how do is, is! and as fit in?

level: juniorimportance: must knowfreq 70%

answer

  1. both accept every value
  2. one keeps static checking
  3. is promotes, as casts
  4. failed as throws TypeError
  5. Object excludes null

basics

~20 s

In Dart, Object? and dynamic both accept any value, including null, but Object? keeps static checking: you test with is or cast with as before using String members. dynamic switches checking off, so calls compile and fail only at runtime.

solid answer

~50 s

`Object` is the superclass of every class except `Null`, so `Object` means any non-null value and `Object?` means any value at all. On such a variable you can only call `Object` members like `toString()`; to use a `String` method you check `if (value is String)`, which promotes a local to `String`, or cast with `value as String`, which throws a `TypeError` if wrong. `is!` is the negated test. `dynamic` also accepts every value, but it **disables static checking**: any member access compiles and is checked at runtime, where a missing member throws `NoSuchMethodError`, and a `dynamic` value can be assigned to a `String` variable without a cast. Effective Dart says to use `Object?` or `Object` unless you really want dynamic dispatch; APIs such as decoded JSON (`Map<String, dynamic>`) are the usual exception, and even there you cast to precise types early.

code

dart · 26 lines
dart
void describe(Object? value) {
  if (value is String) {
    print('name with ${value.length} code units'); // promoted to String
  } else if (value is! num) {
    print('unsupported: ${value.runtimeType}');
  } else {
    print('price ${value * 2}'); // promoted to num
  }
}

void main() {
  describe('Margherita');
  describe(12);

  dynamic raw = 42;
  // raw.toUpperCase(); // compiles, but throws NoSuchMethodError
  try {
    final String name = raw; // implicit downcast compiles
    print(name);
  } on TypeError {
    print('raw was not a String');
  }
  Object boxed = 42;
  // final String bad = boxed; // compile error: needs a cast or a check
  print((boxed as int) + 1); // explicit cast
}

go deeper

for a junior

Recall that Object? accepts anything but keeps checking, while dynamic accepts anything and turns checking off.

for a middle

Explain implicit downcasts from dynamic, promotion after is and is!, and that a failed as throws TypeError.

for a senior

Contain dynamic at API boundaries such as JSON, cast early, and enable strict-casts and avoid_dynamic_calls in the project.

for a principal

Set a codebase policy on dynamic and analyzer strictness that balances migration effort against runtime type failures.

## Three ways to say "anything" Dart's type hierarchy has `Object` at the top of all classes, with one exception: `Null`, the class of `null`, is not a subtype of `Object`. Since sound null safety that gives three types that accept broad sets of values: | Type | Accepts | Static checking | Member access | |---|---|---|---| | `Object` | Every value except `null` | On | Only `Object` members (`toString`, `hashCode`, `==`, `runtimeType`) | | `Object?` | Every value, including `null` | On | Same, plus null checks | | `dynamic` | Every value, including `null` | **Off** | Anything compiles; checked at runtime | The null-safety guide calls `Object?` Dart's top type: if you need "any value", that is the type to write. ## What dynamic really changes `dynamic` is not a bigger `Object`; it is a request to **turn off static type checking** for that expression. dart.dev's built-in types page describes it exactly that way. Two consequences: 1. **Any member access compiles.** `value.toUpperCase()` compiles on a `dynamic` value; if the object has no such member at runtime, Dart throws `NoSuchMethodError`. 2. **Implicit downcasts are allowed.** `String name = value;` compiles when `value` is `dynamic`, and throws a `TypeError` at runtime if it holds, say, an `int`. The same assignment from an `Object` value is a compile-time error (`invalid_assignment`). ## is, is! and as With `Object?` you move from "anything" to a specific type explicitly: - **`is`** tests the runtime type and returns a `bool`. On a local variable, a successful test **promotes** it, so inside `if (value is String) { ... }` you can call `value.length` without a cast. - **`is!`** is the negation: `if (value is! String) return;` also promotes on the path that continues. - **`as`** casts: `value as String` returns the value typed as `String`, or throws a **`TypeError`** if it is not one. Dart 3 removed the old `CastError` class; `TypeError` is what a failed cast throws. Prefer `is` when the value might legitimately be another type, and `as` when any other type is a bug that should fail loudly. ## Menu importer example A menu importer reading a decoded JSON payload receives values typed `dynamic`. Writing `final String name = item['name'];` compiles, and a malformed payload with a number there crashes later with a `TypeError`. Treating the value as `Object?` and testing it keeps the failure where you can handle it: ```dart final Object? raw = item['name']; if (raw is! String) throw FormatException('name must be a string'); final name = raw; // promoted to String ``` ## Tooling that helps - The analyzer's `strict-casts` language mode reports implicit downcasts from `dynamic`, such as passing `jsonDecode(text)` straight to a `List<String>` parameter. - The `avoid_dynamic_calls` lint flags member access on `dynamic` targets. - Effective Dart's rule **"AVOID using `dynamic` unless you want to disable static checking"** states the policy; its companion rule says to annotate with `dynamic` explicitly rather than let inference fail silently. ## dynamic hiding inside generic types `dynamic` often arrives without anyone writing it: - A `Map<String, dynamic>` from decoded JSON makes every `map['key']` a `dynamic` expression. - A `List<dynamic>` makes every element access dynamic, so `items[0].price` compiles whatever the element is. - A declaration whose type inference fails, such as a variable with no initializer and no annotation, is silently `dynamic`. Each of these spreads unchecked code outward: a `dynamic` value assigned to an inferred local makes that local `dynamic` too. The defence is to convert at the boundary, reading `Object?` and checking with `is`, or casting once with `as` into a precise type, so the rest of the program is checked again. ## A short answer to give "`Object?` and `dynamic` both hold any value. `Object?` keeps the analyzer on, so I must prove the type with `is` or assert it with `as`. `dynamic` turns the analyzer off for that value, so mistakes compile and fail at runtime with `NoSuchMethodError` or `TypeError`. I use `Object?` by default and keep `dynamic` at API edges like JSON." ## Summary - Use `Object?` for "any value", `Object` for "any non-null value". - Use `dynamic` only when you deliberately want runtime dispatch or an API hands it to you. - Move from broad to specific types with `is` (safe test and promotion) or `as` (cast that throws `TypeError` on failure).

  • When is dynamic the right type in Dart?
    When you really want runtime dispatch, or when an existing API uses it, such as decoded JSON as `Map<String, dynamic>`. Effective Dart still advises casting those values to precise types early, and annotating `dynamic` explicitly rather than letting inference fall back to it silently.
  • How does the analyzer's strict-casts mode relate to dynamic?
    With `strict-casts: true` under `analyzer: language:` in analysis_options.yaml, the analyzer no longer allows implicit downcasts from `dynamic`, so passing a `dynamic` value where a `List<String>` is expected becomes an error until you add an explicit cast or check. It defaults to false.

saying these in an interview costs you the question

  • dynamic and Object are the same type with different names
  • A failed as cast returns null instead of throwing
  • Calling a missing method on a dynamic value is a compile error
  • Object accepts null, so Object? is redundant
  • Assigning an Object value to a String variable compiles without a cast
open as a page

In a Dart 3 switch statement, do cases fall through, and when do you still write break or continue inside a case?

level: juniorimportance: must knowfreq 50%

basics

~20 s

Dart 3 switch statements never fall through from a non-empty case: its body runs and control leaves the switch, so no break is needed. Empty cases share the next body, and continue with a label jumps into another case.

open as a page

In Dart, how do try, on, catch (e, st) and finally fit together, and when do you use on versus catch?

level: juniorimportance: must knowfreq 70%

basics

~20 s

In Dart, on Type picks which thrown objects a clause handles, catch (e, st) binds the object and its StackTrace, the first matching clause in source order wins, and finally runs whether or not anything was thrown.

open as a page

In Dart, how do required positional, optional positional [ ] and named { } parameters differ, and when do you choose named ones?

level: juniorimportance: must knowfreq 65%

basics

~20 s

Dart functions take required positional parameters first, then either optional positional ones in [ ] or named ones in { }, never both; optional ones need a constant default or a nullable type. Named parameters read clearly and can be skipped individually.

open as a page

In Dart, how do the /, ~/ and % operators differ on int operands, and what do ~/ and % give for negative numbers?

level: juniorimportance: must knowfreq 52%

basics

~20 s

In Dart, / always returns a double, ~/ returns an int truncated toward zero (-7 ~/ 2 is -3), and % is Euclidean modulo whose result is never negative (-5 % 3 is 1); remainder() gives the sign-following remainder.

open as a page

In Dart, what is the difference between declaring a variable final and declaring it const?

level: juniorimportance: must knowfreq 82%

basics

~20 s

In Dart, final means a variable can be assigned only once, with a value that may be computed at runtime; const means its value is a compile-time constant, deeply immutable and canonicalized. Every const variable is implicitly final.

open as a page

In Dart, what is the difference between Exception and Error, and when is catching an Error the wrong move?

level: middleimportance: must knowfreq 62%

basics

~20 s

In Dart, an Error such as ArgumentError or StateError signals a bug the programmer should have prevented; an Exception such as FormatException signals a failure a correct program still meets. Catching an Error hides the bug instead of fixing it.

open as a page

In Dart, what does the cascade .. do, what value does a cascade expression produce, and how does it differ from method chaining?

level: middleimportance: must knowfreq 58%

basics

~10 s

Dart's cascade receiver..member runs a sequence of calls, setters or index assignments on one object, discards each result, and evaluates to the receiver itself, so any API gets fluent style without methods returning this.

open as a page

In Dart, how are int, double and num related, and when does Dart convert between int and double for you?

level: juniorimportance: should knowfreq 52%

basics

~20 s

In Dart, int and double are both subtypes of num. An integer literal becomes a double where a double is expected, as in double z = 1, but a double never converts to int implicitly; you call toInt(), round() or truncate().

open as a page

In Dart, how do string interpolation, raw strings and multi-line strings work, and when is an interpolated string a compile-time constant?

level: juniorimportance: should knowfreq 48%

basics

~20 s

Dart interpolates $name or ${expression} into a string by calling toString(). A raw string (r'...') treats backslashes and $ literally, triple quotes create multi-line strings, and an interpolated string is const only if every interpolated value is a constant null, number, string or bool.

open as a page

In Dart, what does the => arrow syntax mean in a function or member declaration, and what can't you write after it?

level: juniorimportance: should knowfreq 42%

basics

~20 s

In Dart, => expr; is shorthand for { return expr; }. Only an expression may follow the arrow: a conditional or switch expression works, an if statement or loop does not, and => { ... } is a collection literal, not a block.

open as a page

In Dart, how does var infer a local variable's type, and what happens when a var declaration has no initializer?

level: juniorimportance: should knowfreq 60%

basics

~20 s

In Dart, var takes its static type from the initializer, once: var miles = 3 makes miles an int for good, so assigning 2.5 later is a compile error. A var with no initializer gets dynamic, which switches off type checking.

open as a page

In Dart, why can a menu item name containing emoji have a String.length larger than its visible character count, and how do you count characters correctly?

level: middleimportance: should knowfreq 40%

basics

~20 s

A Dart String is a sequence of UTF-16 code units, and length counts those units. Most emoji need two (a surrogate pair), and flags or family emoji combine several code points. Count user-perceived characters with the characters package, e.g. name.characters.length.

open as a page

In Dart's type system, what do void, Never and Null each mean, and where does each typically appear in code?

level: middleimportance: should knowfreq 33%

basics

~20 s

In Dart, void marks a value that must not be used, typically a return type; Never is the bottom type with no values, for expressions that cannot complete, such as throw; and Null is the type whose only value is null, a subtype of every nullable type.

open as a page

In Dart, when does an assert statement actually run, and why must its condition never contain side effects?

level: middleimportance: should knowfreq 42%

basics

~20 s

A Dart assert only runs when the tool enables assertions: Flutter debug mode, dart test, or dart run --enable-asserts. Otherwise the whole statement, arguments included, is skipped, so side effects inside it vanish in release builds.

open as a page

In Dart, how do labelled break and continue work across nested loops, and where do labels stop working?

level: middleimportance: should knowfreq 30%

basics

~20 s

A Dart label (name:) before a loop lets break name; end that whole loop and continue name; start its next iteration from inside nested loops; labels cannot be reached from inside a closure, so you cannot break out of forEach.

open as a page

In Dart, how do you define a custom exception class, and why implement Exception rather than throw a plain String?

level: middleimportance: should knowfreq 44%

basics

~20 s

Dart can throw any non-null object, but a custom exception should be a class that implements Exception, carries fields describing the failure and overrides toString, so callers can catch it precisely with an on clause and read its data.

open as a page

In Dart, how does rethrow differ from throw e inside a catch, and when do you need Error.throwWithStackTrace?

level: middleimportance: should knowfreq 38%

basics

~20 s

Inside a Dart catch, rethrow re-throws the caught object with its original stack trace, while throw e starts a new trace at the catch. Error.throwWithStackTrace (Dart 2.16+) throws any object with a trace you supply, for translating exceptions or throwing outside a catch.

open as a page

In Dart, why must a parameter's default value be a compile-time constant, and how do you default to something like DateTime.now()?

level: middleimportance: should knowfreq 38%

basics

~20 s

Dart parameter defaults must be compile-time constants, so DateTime.now() or a fresh list cannot be a default. Declare the parameter nullable and resolve it with ?? in the body; defaults apply only when the argument is omitted, not when null is passed.

open as a page

In Dart, when should a function be top-level, static or an instance method, and why does Effective Dart discourage static-only classes?

level: middleimportance: should knowfreq 32%

basics

~20 s

Dart functions can be top-level, static or instance methods: instance for behaviour that needs an object's state, static for type-tied factories and parsers, and top-level for standalone helpers and main. Effective Dart avoids static-only classes because libraries already provide namespaces.

open as a page

In Dart 3.10 and later, how does a dot shorthand like .start or .parse('8080') resolve, and where does it fail to compile?

level: middleimportance: should knowfreq 40%

basics

~20 s

A Dart dot shorthand such as .start omits the type name and is resolved against the context type, the type expected at that position; it fails where no context exists, like var x = .a, or where that type lacks the member.

open as a page

In Dart, what does it mean that const values are canonicalized, and which expressions may appear in a const initializer?

level: middleimportance: should knowfreq 45%

basics

~20 s

Dart evaluates const expressions at compile time and keeps one instance per distinct constant value, so equal constants are identical(). A const initializer may use literals, other constants, arithmetic on constant numbers, is/as, collection if, spreads and const constructor calls, not arbitrary function calls.

open as a page

In Dart, why can you add items to a list held in a final variable, and what changes if the list is const?

level: middleimportance: should knowfreq 58%

basics

~20 s

final freezes only the variable binding, so the list it references stays mutable and add() works. A const list is a deeply immutable constant: add() still compiles but throws UnsupportedError at runtime, and everything inside a constant is constant too.

open as a page

A Dart menu importer passes native tests, but compiled to JavaScript for the web it prints 20.0 as 20, sees 1.0 as an int and garbles large item IDs. Why?

level: seniorimportance: should knowfreq 28%

basics

~20 s

When Dart compiles to JavaScript, int and double share one 64-bit floating-point representation, so an int is a double with no fractional part. 1.0 is int is true, 20.0 prints as 20, and integers beyond 2^53 lose precision.

open as a page

In Dart, a for-in loop notifying a List of listeners throws ConcurrentModificationError when one listener unsubscribes itself; why, and how do you fix it?

level: seniorimportance: should knowfreq 34%

basics

~10 s

A Dart for-in loop drives the list's Iterator, and changing a growable List's length between moveNext calls throws ConcurrentModificationError. Iterate a snapshot such as List.of(listeners), or defer removals until the loop ends.

open as a page

A Dart CSV importer must report every bad row without aborting the whole file; how would you structure its exception handling?

level: seniorimportance: should knowfreq 30%

basics

~20 s

In a Dart importer, give each row its own try with on RowException, record row, column and message in a report and continue; let file-level exceptions end the import, and never catch Error, which means the importer is buggy.

open as a page

When designing a public Dart API such as a formatting helper, how do you choose between named and optional positional parameters with future changes in mind?

level: seniorimportance: should knowfreq 28%

basics

~20 s

In a public Dart API, keep the obvious subject positional and make options named with constant defaults: calls stay readable, booleans explain themselves, and new named options break no caller, though overriders of a method must still add them.

open as a page

In Dart, why do expressions like -1.abs(), await fetchUsers().length and cond ? a : b..add(x) not parse the way they read?

level: seniorimportance: should knowfreq 30%

basics

~20 s

In Dart, member access binds tighter than prefix operators, so -1.abs() is -(1.abs()) and await f().length awaits the length; a cascade binds looser than ?:, so b..add(x) after a conditional mutates whichever branch was chosen.

open as a page

A Dart service's first unit conversion after startup is slow and sometimes throws from a top-level final lookup table. Why, and how would you fix it?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Dart initializes top-level and static variables lazily, the first time they are read, so the table's costly or failing initializer runs inside the first request, not at startup. Make the table const if it is fixed data, or build it explicitly during startup.

open as a page

In Dart 3.12 and later, what does a private named parameter like {required this._currency} do, and where is it not allowed?

level: middleimportance: nice to knowfreq 18%

basics

~20 s

Since Dart 3.12 a constructor can write {required this._currency}: the field stays private while callers pass currency:. It works only for initializing formals, not for ordinary named parameters, and replaces an initializer list that just stripped the underscore.

open as a page

showing 1–30 of 31