In Dart, why must a parameter's default value be a compile-time constant, and how do you default to something like DateTime.now()?
answer
- evaluated once, not per call
- const [] is unmodifiable
- nullable parameter plus ??
- omitted is not the same as null
- no explicit = null
basics
~20 sDart 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.
solid answer
~40 sA default written with `=` must be a constant expression: a literal, a `const` value or a const constructor call. It is fixed at compile time, so `{DateTime at = DateTime.now()}` is rejected, and a `const []` default is unmodifiable. For computed defaults I declare the parameter nullable and write `final when = at ?? DateTime.now();`, or do it in a constructor's initializer list. One subtlety: a default only applies when the argument is **omitted**; passing `null` explicitly to `{String? name = 'guest'}` gives `null`, which bites wrappers that forward their own nullable values. Effective Dart also says not to write `= null` explicitly, since that is already the implicit default of a nullable optional parameter.
code
dart · 14 linesString formatTimestamp(DateTime? at, {String separator = ' ', List<String>? tags}) {
final when = at ?? DateTime.now(); // computed default
final allTags = [...?tags, 'generated']; // a fresh growable list
return '${when.toIso8601String()}$separator${allTags.join(',')}';
}
String greet({String? name = 'guest'}) => 'Hi $name';
void main() {
print(greet()); // Hi guest
print(greet(name: null)); // Hi null: the default is not used
print(formatTimestamp(DateTime.utc(2026, 1, 2), tags: ['draft']));
// 2026-01-02T00:00:00.000Z draft,generated
}go deeper
Recall that parameter defaults must be constants, and that a nullable optional parameter without a default is null when omitted.
Explain the nullable plus ?? pattern for computed defaults and that an explicit null bypasses a default value.
Design forwarding wrappers and widget constructors so explicit nulls do not silently override defaults, and test that path.
Standardise how shared APIs express optionality: non-nullable parameters with constant defaults where possible, and documented null semantics elsewhere.
## The rule A default value for an optional parameter, written with `=`, **must be a compile-time constant**: a literal, a `const` variable, a `const` constructor call, a const collection. The dart.dev guide states it for both named and optional positional parameters. Anything that runs code at call time, such as `DateTime.now()`, `[]` without `const`, or a call to a function, is rejected. Constants are required because Dart evaluates the default **once, at compile time**, and reuses it for every call. That is also why a default can never be a mutable object shared between calls by accident: a `const []` default is an **unmodifiable** list. ## Defaulting to something non-constant The standard pattern is a **nullable parameter plus `??`** inside the function: ```dart String formatTimestamp(DateTime? at, {String? locale}) { final when = at ?? DateTime.now(); final lang = locale ?? 'en'; // ... } ``` In a constructor, the same pattern goes in the initializer list: `Report({DateTime? createdAt}) : createdAt = createdAt ?? DateTime.now();`. For a collection that callers may extend, default to `null` and create a fresh growable list inside, rather than defaulting to `const []` and later calling `add` on it, which throws an `UnsupportedError` at runtime. ## Omitted versus explicitly `null` A default applies **only when the argument is omitted**. If a caller explicitly passes `null` to a nullable parameter that has a default, the parameter is `null`: ```dart String greet({String? name = 'guest'}) => 'Hi $name'; greet(); // Hi guest greet(name: null); // Hi null ``` This matters when you forward values: - A wrapper that passes `name: widget.name` through to such a function sends `null` whenever its own value is `null`, silently bypassing the default. - Two ways to handle it: make the parameter non-nullable with a default (so `null` is rejected at compile time), or treat `null` as "use the default" with `??` in the body. ## Related style rules | Situation | What to write | |---|---| | Nullable optional parameter, default is `null` | leave the default out; `avoid_init_to_null` flags `= null` | | Default is a real constant | `{int decimals = 2}` | | Default must be computed | nullable parameter plus `??` in the body | | Callers would pass `null` or `''` to mean "not given" | make the parameter optional instead | Effective Dart puts two of these into words: **don't** write an explicit default of `null`, and **avoid** mandatory parameters that accept a special "no argument" value such as `null` or an empty string; let callers omit the argument instead. ## Checking the design 1. List the parameters that have no sensible constant default. Make each nullable and resolve it in the body. 2. For each nullable parameter with a default, decide what an explicit `null` should mean, and document it. 3. Prefer non-nullable parameters with constant defaults where `null` has no meaning; the type system then rules out the ambiguity. 4. Add a test for the explicit-`null` path of any wrapper that forwards optional values. ## What an interviewer listens for - "Defaults must be compile-time constants." - The `nullable + ??` pattern for `DateTime.now()` or a fresh list. - The omitted-versus-explicit-`null` distinction and how a forwarding wrapper trips over it. - Effective Dart's advice to omit `= null`.
- What goes wrong if a Dart parameter defaults to const [] and the function adds to it?A `const` list is unmodifiable, so calling `add` on it throws an `UnsupportedError` at runtime when the caller omitted the argument, while calls that pass their own growable list work. Default to `null` instead and build a fresh list in the body, or copy the argument with `[...?items]` before changing it.
- How would you make a Dart wrapper preserve a callee's default when its own optional value is null?Either resolve it in the callee by treating `null` as "use the default" with `??`, or, in the wrapper, avoid passing the argument when it is `null`, for example by branching between two calls. Making the callee's parameter non-nullable with a constant default also works, since then the wrapper cannot pass `null` at all.
saying these in an interview costs you the question
- Writes DateTime.now() as a parameter default
- Believes passing null explicitly triggers the default value
- Adds = null to every nullable optional parameter
- Mutates a const [] default and expects it to work
- Thinks the default is re-evaluated on every call