site-www
site-www copied to clipboard
Improve setters and getters examples on 'Methods' page
Page URL
https://dart.dev/language/methods/
Page source
https://github.com/dart-lang/site-www/tree/main/src/content/language/methods.md
Describe the problem
At
https://dart.dev/language/methods#getters-and-setters
we read about getters and setters but the text feels much too short and the example could be extended (the example code also does not really tell a good story, IMHO).
Suggesting more examples to illustrate various setter/getter "do's" and "don'ts" (including one involving a final field that creates a recursive call, see below) that tell a more structured story. Especially for people coming from Java (like me) this is helpful.
Note on terms: I am using "synthetic field" for a setter/getter that simulates the presence of field, not sure whether this is the correct term.
Here we go:
import 'dart:math';
// A class with some fields.
class Example {
int a;
int _b;
final int c;
static int d = 1000;
Example(this.a,this._b,this.c);
}
// You will get default getters and setters on class "Example":
void handleExample() {
final ex = Example(1,2,3);
// There will be a setter and getter for field "a".
final v = ex.a;
ex.a = 10;
ex.a++;
assert(ex.a == 11);
// There will be a setter and getter for field "_b".
// But both are not visible outside of the library (this file)
final u = ex._b;
ex._b = 20;
assert(ex._b == 20);
// There will be a getter and getter for field "c", but no setter.
final w = ex.c;
// ex.c = 10; // NO! "'c' cannot be used as a setter"
// There will be a static getter and getter for static field "d".
final z = Example.d;
Example.d = 10;
Example.d++;
assert(Example.d == 11);
}
// You cannot override a getter or setter with a method.
// Moreover, the actual setter name for field "a" is really "a="
// instead of "a". "a=" is not a valid name for a manually written
// method, so you cannot even name the setter (that's how I understand
// it at least.)
class ExampleFaulty extends Example {
// Both
// ExampleFaulty(super.a, super.b, super.c);
// and
// ExampleFaulty(super.a, super._b, super.c);
// work here.
ExampleFaulty(super.a, super.b, super.c);
// This will NOT compile:
int a() {
return a;
}
// This will NOT compile:
void a(int x) {
a = x;
}
}
// You can define Java-style getX() and setX() methods.
// They are just common methods, nothing special.
class ExampleJavaStyleGetterSetter extends Example {
ExampleJavaStyleGetterSetter(super.a, super.b, super.c);
int getA() {
return a;
}
void setA(int x) {
a = x;
}
}
// You can override the default setter and getter of a field
// in a subclass. There is a function syntax and a standard syntax
// to do that.
class ExampleOverrideGetterSetterOfA1 extends Example {
ExampleOverrideGetterSetterOfA1(super.a, super.b, super.c);
set a(int x) => a = x;
int get a => a;
}
class ExampleOverrideAccessorsOfA2 extends Example {
ExampleOverrideAccessorsOfA2(super.a, super.b, super.c);
set a(int x) {
print("Setter for 'a' has been called");
a = x;
}
int get a {
print("Getter for 'a' has been called");
return a;
}
}
// You CANNOT override the implicit setter and getter of a non-final field.
// in the same class (as opposed to in a superclass.) You will get a
// "duplicate_definition" error ("The name 'a' is already defined")
class ExampleFaultyOverridingGetterSetter {
int a = 1;
// Both of these will NOT compile:
set a(int x) => a = x;
int get a => a;
// Both of these will NOT compile either:
set a(int x) {
a = x;
}
int get a {
return a;
}
}
// You SEEMINGLY can add a setter for a final field!
// But this is actually just an endless recursive call
// that will lead to a stack overflow.
class ExampleOverridingSetterOnFinalField {
final int a = 1;
// DON'T DO THIS, even if it compiles!
set a(int x) => a = x;
}
// You can have a setter and getter for a "synthetic field",
// here the "opposite" of "angle", rotated by Pi (180°)
class ExampleSyntheticField {
double angle = 0.0;
static double _canonicalize(double x) {
if (x >= 0.0) {
return x.remainder(2.0*pi);
}
else {
return 2*pi + x.remainder(2.0*pi);
}
}
double get opposite => _canonicalize(angle + pi);
set opposite(double x) => angle = _canonicalize(x - pi);
}
// The following output is produced by the example code:
// The opposite of 0.5 π is 1.5 π
// If the opposite is 0.5 π, the angle is 1.5 π
// If the opposite is 0.7499999999999997 π, the angle is 1.75 π
void handleExampleSyntheticField() {
final ExampleSyntheticField obj = ExampleSyntheticField();
obj.angle = 0.5 * pi;
print("The opposite of ${obj.angle/pi} π is ${obj.opposite/pi} π");
obj.opposite = 0.5 * pi;
print("If the opposite is ${obj.opposite/pi} π, the angle is ${obj.angle/pi} π");
obj.opposite += 0.25 * pi;
print("If the opposite is ${obj.opposite/pi} π, the angle is ${obj.angle/pi} π");
}
void main() {
handleExample();
}
Expected fix
No response
Additional context
No response
I would like to fix this problem.
- [ ] I will try and fix this problem on dart.dev.