Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify use of this in initializing instance variables #5310

Merged
merged 17 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions examples/misc/lib/language_tour/classes/point_this.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ignore_for_file: invalid_reference_to_this, unnecessary_this
double initialX = 1.5;

class Point {
// OK, can access declarations that do not depend on `this`:
double? x = initialX;

// ERROR, can't access `this` in non-`late` initializer:
double? y = this.x;

// OK, can access `this` in `late` initializer:
late double? z = this.x;

// OK, `this.fieldName` is a parameter declaration, not an expression:
Point(this.x, this.y);
}
36 changes: 30 additions & 6 deletions src/language/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,16 @@ class Point {
}
```

All uninitialized instance variables have the value `null`.
An uninitialized instance variable declared with a
[nullable type][] has the value `null`.
Non-nullable instance variables [must be initialized][] at declaration.

All instance variables generate an implicit *getter* method.
Non-final instance variables and
`late final` instance variables without initializers also generate
an implicit *setter* method. For details,
check out [Getters and setters][].

If you initialize a non-`late` instance variable where it's declared,
the value is set when the instance is created,
which is before the constructor and its initializer list execute.
As a result, non-`late` instance variable initializers can't access `this`.

<?code-excerpt "misc/lib/language_tour/classes/point_with_main.dart (class+main)" replace="/(double .*?;).*/$1/g" plaster="none"?>
```dart
class Point {
Expand All @@ -195,6 +192,31 @@ void main() {
}
```

Initializing a non-`late` instance variable where it's declared
sets the value when the instance is created,
before the constructor and its initializer list execute.
As a result, the initializing expression (after the `=`)
of a non-`late` instance variable can't access `this`.

<?code-excerpt "misc/lib/language_tour/classes/point_this.dart"?>
```dart
double initialX = 1.5;

class Point {
// OK, can access declarations that do not depend on `this`:
double? x = initialX;

// ERROR, can't access `this` in non-`late` initializer:
double? y = this.x;

// OK, can access `this` in `late` initializer:
late double? z = this.x;

// OK, `this.fieldName` is a parameter declaration, not an expression:
Point(this.x, this.y);
}
```
MaryaBelanger marked this conversation as resolved.
Show resolved Hide resolved

Instance variables can be `final`,
in which case they must be set exactly once.
Initialize `final`, non-`late` instance variables
Expand Down Expand Up @@ -350,3 +372,5 @@ can pass a static method as a parameter to a constant constructor.
[initializer list]: /language/constructors#initializer-list
[factory constructor]: /language/constructors#factory-constructors
[late-final-ivar]: /effective-dart/design#avoid-public-late-final-fields-without-initializers
[nullable type]: /null-safety/understanding-null-safety#using-nullable-types
[must be initialized]: /null-safety/understanding-null-safety#uninitialized-variables