skip to content

Functions & Parameters

Dart functions take positional, optional positional and named parameters with defaults, arrow bodies and a main entry point. Interviewers ask when to choose named over optional positional arguments.

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

explore

questions

6

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

level: juniorimportance: must knowfreq 65%

answer

  1. positional first, then one optional group
  2. square brackets or braces, not both
  3. constant default or nullable type
  4. readable call sites, skip any option
  5. Flutter constructors are all named

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.

solid answer

~40 s

Required positional parameters are passed in order and cannot be omitted. After them a function may declare **either** optional positional parameters in `[ ]` **or** named parameters in `{ }`, but not both groups. Optional parameters need a compile-time-constant default or a nullable type whose implicit default is `null`; a named one can be marked `required` instead. I choose named parameters when there are several options or any booleans, because `formatPrice(99, decimals: 0, showSign: true)` explains itself and callers can skip any subset; optional positional only fits a short natural progression like `DateTime(year, [month, day])`. Since Dart 2.17 named arguments may appear anywhere in a call, and Flutter widget constructors rely on named parameters throughout.

code

dart · 19 lines
dart
String formatPrice(
  num amount, {
  String currency = 'EUR',
  int decimals = 2,
  bool showSign = false,
}) {
  final sign = showSign && amount > 0 ? '+' : '';
  return '$sign${amount.toStringAsFixed(decimals)} $currency';
}

String pad(String text, [int width = 10, String fill = ' ']) =>
    text.padLeft(width, fill);

void main() {
  print(formatPrice(1299.99)); // 1299.99 EUR
  print(formatPrice(1299.99, decimals: 0, showSign: true)); // +1300 EUR
  print(pad('42')); // '        42'
  print(pad('42', 5, '0')); // 00042
}

go deeper

for a junior

Recall the three kinds, the square-bracket and brace syntax, and that optional parameters need a constant default or a nullable type.

for a middle

Explain why a function has at most one optional group, how defaults and nullable types interact, and why Flutter constructors use named parameters.

for a senior

Choose parameter kinds for API readability and evolution: named for options and booleans, optional positional only for a natural progression.

for a principal

Set API conventions for shared packages, including named parameters for anything optional and the Dart 3.13 parameter-modifier rule during upgrades.

## Three kinds of parameters A Dart function declares its parameters in up to two groups: 1. **Required positional parameters** come first, in order: `String formatPrice(num amount)`. Every call must pass them, by position. 2. Then **either** a group of **optional positional** parameters in square brackets, `[String currency = 'EUR']`, **or** a group of **named** parameters in braces, `{int decimals = 2, bool showSign = false}`. A single function cannot have both groups. | | Declared as | Passed as | Optional? | |---|---|---|---| | Required positional | `f(int a)` | `f(1)` | no | | Optional positional | `f([int a = 0])` | `f()` or `f(1)` | yes | | Named | `f({int a = 0})` | `f()` or `f(a: 1)` | yes, unless marked `required` | ## Defaults and nullability An optional parameter, positional or named, needs a way to have a value when the caller leaves it out: - give it a **default value** with `=`; the default must be a **compile-time constant**; - or make its type **nullable**, in which case the implicit default is `null`: `[String? device]`, `{bool? bold}`; - a named parameter can instead be marked **`required`**, so the analyzer rejects calls that omit it. The rules around `required` are part of null safety and covered there. A non-nullable optional parameter with no default is a compile error, because `null` would be its only possible default. ## Why named parameters dominate Dart APIs Named arguments make call sites readable, especially for booleans and numbers whose meaning is not obvious from the value: ```dart formatPrice(1299.5, decimals: 0, showSign: true); // versus a positional mystery: formatPriceOld(1299.5, 'EUR', 0, true); ``` They also let callers skip any subset of options, which optional positional parameters cannot do without passing every earlier one. That is why Flutter widget constructors use named parameters almost exclusively, even for mandatory ones such as a `child`, marked `required`. Since Dart 2.17, **named arguments can appear anywhere in the argument list**, not only after the positional ones. That is what makes `repeat(times: 2, () { ... })` legal, with a trailing callback after a named argument. ## When optional positional still fits Optional positional parameters suit a short, natural progression where earlier arguments are passed more often than later ones. The SDK's own examples are `String.fromCharCodes(charCodes, [start = 0, end])` and the `DateTime(year, [month = 1, day = 1, ...])` constructor. If a caller might want to pass a later one while omitting an earlier one, switch to named. ## Parameter modifiers in Dart 3.13 Since Dart 3.13, `final` and `var` on an ordinary function, method, closure or in-body constructor parameter are a **compile-time error** (`extraneous_modifier`); those modifiers are reserved for primary constructors, where they declare fields. To keep parameters from being reassigned as a style rule, enable the `parameter_assignments` lint. ## Common mistakes - **Mixing both optional groups**: `f(int a, [int b = 0], {int c = 0})` is rejected; pick one. - **A non-constant default**: `{DateTime at = DateTime.now()}` does not compile. Use a nullable parameter and resolve it in the body. - **Booleans passed by position**: `formatPrice(9.99, 'EUR', 0, true)` compiles, but nobody can read it in review, and swapping two same-typed arguments goes unnoticed. - **Treating named as required**: a named parameter without `required` is optional, so a caller can silently omit it and get the default. - **Explicit `= null` defaults**: a nullable optional parameter already defaults to `null`; the `avoid_init_to_null` lint, in the `recommended` and `flutter` sets, flags the redundant form. ## What an interviewer listens for - The three kinds and the "positional first, then `[]` or `{}` but not both" rule. - Constant defaults and the nullable alternative. - A reason for choosing named parameters: readability and skipping. - Awareness that Flutter APIs are built on named parameters.

  • Why does void log(final String message) stop compiling when a package moves to Dart 3.13?
    Dart 3.13 reserves `final` and `var` on parameters for primary constructors, where they declare fields. On an ordinary function, method, closure or in-body constructor parameter they are now an `extraneous_modifier` compile error. Remove the modifier, or run `dart fix`; if the team wants non-reassignable parameters as a style rule, enable the `parameter_assignments` lint.
  • Can a single Dart function declare both optional positional and named parameters?
    No. After the required positional parameters, a function has at most one optional group: either `[ ]` positional or `{ }` named. If you need both kinds of flexibility, make the optional values named, which also keeps call sites readable.
  • In a Dart call, must named arguments come after positional ones?
    Not since Dart 2.17. Named arguments can appear anywhere in the argument list, so `repeat(times: 2, () { ... })` is valid and lets a trailing callback sit last for readability. The parameters are still declared positional-first in the function signature.

saying these in an interview costs you the question

  • Thinks a function can mix [ ] and { } optional parameters
  • Believes named parameters are always required
  • Uses a non-constant expression as a default value
  • Declares a non-nullable optional parameter without a default
  • Says named arguments must come last in a call
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, 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

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 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