prefer-final-parameters

Same as prefer_final_parameters in Dart lints

Group
Style
Path
lint/style/prefer-final-parameters
Default
Off, opt in
Origin
Dart lints
Rule
357 of 512

Prefer final for parameters that are never reassigned.

Declaring a parameter final documents that the function never rebinds it and lets the compiler enforce that. Every parameter of a function, method, setter, operator, constructor, local function, or function literal is checked, unless it is already final, is an initializing formal or an extension-type representation formal (implicitly final), is the wildcard _ (Dart 3.7+; in older libraries _ is an ordinary name and is checked), or is written anywhere in the body (including from closures). Function-typed formals (void f(int callback())) are checked like any other parameter. Like the official lint, the rule is off in libraries with primary constructors enabled (Dart 3.13+).

void greet(String name) => print(name); // flagged
void greet(final String name) => print(name); // ok

Invalid

example.dartdart
// @dart = 3.12
class Counter {
  int count = 0;
  final String label;

  Counter(int start, this.label) : count = start;

  void add(int amount) {
    count += amount;
  }

  set value(int v) => count = v;

  Counter operator +(Counter other) => Counter(count + other.count, label);

}

abstract class Shape {
  void resize(double factor);
}

void greet(String name, {String greeting = 'Hi'}) {
  print('$greeting $name');
}

void closures(List<int> items) {
  items.forEach((item) => print(item));
  void local(int x) {
    print(x);
  }

  local(1);
}

// Function-typed formals cannot be `final`, but the analyzer still reports them.
void callback(void cb(final int x)) {
  cb(1);
}

// Ordinary constructors and methods still have rebindable parameters.
extension type Wrapper(int value) {
  Wrapper.from(int input) : this(input);
  int plus(int amount) => value + amount;
}
The parameter `start` should be `final`.
5
6 Counter(int start, this.label) : count = start;
The parameter `amount` should be `final`.
7
8 void add(int amount) {
The parameter `v` should be `final`.
11
12 set value(int v) => count = v;
The parameter `other` should be `final`.
13
14 Counter operator +(Counter other) => Counter(count + other.count, label);
The parameter `factor` should be `final`.
18abstract class Shape {
19 void resize(double factor);
The parameter `name` should be `final`.
21
22void greet(String name, {String greeting = 'Hi'}) {
The parameter `greeting` should be `final`.
21
22void greet(String name, {String greeting = 'Hi'}) {
The parameter `items` should be `final`.
25
26void closures(List<int> items) {
The parameter `item` should be `final`.
26void closures(List<int> items) {
27 items.forEach((item) => print(item));
The parameter `x` should be `final`.
27 items.forEach((item) => print(item));
28 void local(int x) {
The parameter `cb` should be `final`.
35// Function-typed formals cannot be `final`, but the analyzer still reports them.
36void callback(void cb(final int x)) {
The parameter `input` should be `final`.
41extension type Wrapper(int value) {
42 Wrapper.from(int input) : this(input);
The parameter `amount` should be `final`.
42 Wrapper.from(int input) : this(input);
43 int plus(int amount) => value + amount;

Valid

example.dartdart
// @dart = 3.12
class Counter {
  int count = 0;
  final String label;

  Counter(final int start, this.label) : count = start;

  Counter.named(this.count, this.label);

  void add(final int amount) {
    count += amount;
  }

  void reset(int to) {
    to = to.clamp(0, 10);
    count = to;
  }

  set value(final int v) => count = v;
}

class Child extends Counter {
  Child(super.count, super.label);
}

void greet(final String name, {final String greeting = 'Hi'}) {
  print('$greeting $name');
}

void wildcard(final int _) {}

void closures(final List<int> items) {
  items.forEach((final item) => print(item));
  void local(int x) {
    void inner() {
      x = 2;
    }

    inner();
  }

  local(1);
}

// Representation formals declare final fields, even without `final`.
extension type Identifier(int value) {}
extension type const NamedIdentifier._(int value) {}
extension type Pair((int, int) value) {}
extension type WildcardIdentifier(int _) {}

Configure prefer-final-parameters

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-final-parameters": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/prefer-final-parameters: <reason>