Skip to content

prefer_private_named_parameters

v0.7.0WarningFixConfigurableCode Quality

Warns when a constructor declares a public named parameter whose only purpose is to initialize a private field of the same name through the initializer list. Since Dart 3.12, a named initializing formal can be private directly (this._name), and callers still use the public name.

Before Dart 3.12, a named parameter could not start with an underscore, so initializing a private field from a named parameter required boilerplate: declare a public parameter, then assign it in the initializer list. Dart 3.12 removes that restriction — Foo({required this._name}) is valid and is still called as Foo(name: ...).

See also: Announcing Dart 3.12 | Constructors: Initializing formal parameters

Three parameters that exist only to be copied into three fields:

class UserRepository {
final HttpClient _client;
final Cache _cache;
final Logger _logger;
UserRepository({
required HttpClient client,
required Cache cache,
required Logger logger,
}) : _client = client,
_cache = cache,
_logger = logger;
}
class HttpClient {}
class Cache {}
class Logger {}

The initializer list disappears; call sites are unchanged — UserRepository(client: ..., cache: ..., logger: ...):

class UserRepository {
final HttpClient _client;
final Cache _cache;
final Logger _logger;
UserRepository({
required this._client,
required this._cache,
required this._logger,
});
}
class HttpClient {}
class Cache {}
class Logger {}

The quick fix does this rewrite.

By default only a parameter whose name matches its field (client → _client) is reported. Set only_same_name: false to also flag one that was renamed on the way in:

analysis_options.yaml
many_lints:
rules:
prefer_private_named_parameters:
only_same_name: false
class Account {
final String _id;
// Reported only under `only_same_name: false`.
Account({required String identifier}) : _id = identifier;
}

The quick fix declines these: adopting the shorthand would rename the named argument from identifier to id, breaking every call site. The diagnostic tells you; the edit is yours.

The rule only reports when the conversion is behaviour-preserving:

The parameter is used solely in that one initializer. A parameter also read in the body or in an assertion is doing more than copying.

Its declared type matches the field type. A widening or narrowing conversion is not a rename.

The library is on language version 3.12 or later. A file pinned to an older version is skipped, since the shorthand would not compile there.

Only named parameters. A positional Foo(String name) : _name = name is not covered — positional initializing formals could always be written as this._name.

Function-typed parameters are skipped. Foo({required void Function() onTap}) : _onTap = onTap keeps its shape; converting it would lose the written signature.

Only a single leading underscore. A field named __cache is not reported.

This rule is in the opinionated preset, so it is on with preset: opinionated, or by name:

many_lints.yaml
rules:
prefer_private_named_parameters: true

To turn it off again:

many_lints.yaml
rules:
prefer_private_named_parameters: false

To keep the rule on but skip certain paths, use per-rule exclude.

analysis_options.yaml
many_lints:
rules:
prefer_private_named_parameters:
only_same_name: false
Option Type Default Description
only_same_name bool true When false, also report a parameter whose name differs from the field (_id from identifier). The quick fix declines those — adopting the shorthand renames the named argument, which breaks call sites