146 lines
3.9 KiB
Plaintext
146 lines
3.9 KiB
Plaintext
Initializing formals of https://dart.dev/language/constructors#generative-constructors[generative constructors] should be used as a way to assign the value of a constructor parameter to a field, whenever that is possible.
|
|
|
|
== Why is this an issue?
|
|
|
|
Generative constructors in Dart support initializing formals, which are a concise way to assign the value of a constructor parameter to a field.
|
|
|
|
[source,dart]
|
|
----
|
|
class Point {
|
|
final int x;
|
|
final int y;
|
|
|
|
Point(this.x, this.y);
|
|
}
|
|
----
|
|
|
|
Their use makes the code more concise and less error-prone than manual initialization:
|
|
|
|
* there is reduced risk of a mismatch between the type of the parameter and the type of the field, because the initializing formal type can (and usually is) omitted, in favor of the field type
|
|
* there is no risk of a mismatch between the name of the parameter and the name of the field, because the compiler emits an error if it can't find a field with the same name as the initializing formals
|
|
* there is no risk of forgetting to assign the parameter to the field in the body of the constructor
|
|
* there is no risk of wrongly assigning the parameter to itself, which can happen by forgetting to use the `this` keyword: `value = value` instead of `this.value = value`
|
|
|
|
=== Exceptions
|
|
|
|
The rule doesn't apply when the constructor has to perform additional logic before assigning the parameter to the field, for at least one of the parameters, because in that scenario there is not a one-to-one correspondence between the parameter and the field anymore.
|
|
|
|
[source,dart]
|
|
----
|
|
class AClass {
|
|
int value1 = 1;
|
|
int value2 = 2;
|
|
|
|
AClass(int value1, int value2) {
|
|
value1 += value2; // value1 is modified before being assigned
|
|
this.value1 = value1; // Non applicable
|
|
this.value2 = value2; // Non applicable
|
|
}
|
|
}
|
|
----
|
|
|
|
The rule applies, however, when the constructor checks for preconditions on the value of the parameter, because the check can be done with initializing formals as well.
|
|
|
|
[source,dart]
|
|
----
|
|
class AClass {
|
|
int value1 = 1;
|
|
|
|
AClass(int value1, int value2) {
|
|
if (value1 >= 0) {
|
|
throw Exception('value1 must be negative');
|
|
}
|
|
this.value1 = value1; // Noncompliant
|
|
}
|
|
}
|
|
----
|
|
|
|
== How to fix it
|
|
|
|
Rely on https://dart.dev/language/constructors#generative-constructors[generative constructors] whenever fields have to be initialized with constructor parameters.
|
|
|
|
If there are preconditions to be checked on the value of the parameter, it can be done in the body of the constructor, referring to the initializing formal parameter directly.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,dart,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
class Point {
|
|
int? x;
|
|
int? y;
|
|
|
|
Point(int x, int y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,dart,diff-id=1,diff-type=compliant]
|
|
----
|
|
class Point {
|
|
int x;
|
|
int y;
|
|
|
|
Point(this.x, this.y);
|
|
}
|
|
----
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,dart,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
class AClass {
|
|
int value1 = 1;
|
|
|
|
AClass(int value1, int value2) {
|
|
if (value1 >= 0) {
|
|
throw Exception('value1 must be negative');
|
|
}
|
|
this.value1 = value1; // Noncompliant
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,dart,diff-id=2,diff-type=compliant]
|
|
----
|
|
class AClass {
|
|
int value1 = 1;
|
|
|
|
AClass(this.value1, int value2) {
|
|
if (value1 >= 0) {
|
|
throw Exception('value1 must be negative');
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* Dart Docs - https://dart.dev/tools/linter-rules/prefer_initializing_formals[Dart Linter rule - prefer_initializing_formals]
|
|
* Dart Docs - https://dart.dev/language/constructors#generative-constructors[Language - Generative constructors]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Use an initializing formal to assign a parameter to a field.
|
|
|
|
=== Highlighting
|
|
|
|
The entire assignment expression: e.g. `this.value = value`.
|
|
|
|
endif::env-github,rspecator-view[]
|