Q&A
What are the setter and getter methods in Dart?
Overview
Dart fields are public by default - you can access them directly. Getters and setters are the Dart-idiomatic way to add controlled access: validation in a setter, computed values in a getter, or lazy initialization, all while preserving clean obj.property / obj.property = value syntax instead of obj.getProperty() / obj.setProperty(...).
graph LR
A["obj.temperature"] --> B["Getter runs → returns value"]
C["obj.temperature = 37"] --> D["Setter runs → validates & stores"]
style B fill:#1e1b4b,color:#fff
style D fill:#1e1b4b,color:#fff
Basic Getter and Setter
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
// Getter: computed property (no stored 'area' field)
double get area => _width * _height;
// Getter with validation access
double get width => _width;
// Setter with validation
set width(double value) {
if (value <= 0) throw ArgumentError('Width must be positive');
_width = value;
}
double get height => _height;
set height(double value) {
if (value <= 0) throw ArgumentError('Height must be positive');
_height = value;
}
}
final rect = Rectangle(4, 5);
print(rect.area); // 20.0 - read via getter, no ()
rect.width = 10; // setter runs with validation
rect.width = -1; // throws ArgumentError
Note the convention: backing fields use a _ prefix (private in Dart's library scope) while the public API uses the getter/setter without the underscore.
Read-Only Property (getter only, no setter)
class Circle {
final double radius;
Circle(this.radius);
double get circumference => 2 * 3.14159 * radius;
double get area => 3.14159 * radius * radius;
}
final c = Circle(5);
print(c.area); // 78.53975
c.area = 10; // ❌ compile error: no setter defined
Defining only a getter makes the property effectively read-only.
Getter for Lazy Initialization
Compute and cache an expensive value on first access:
class Config {
List<String>? _cachedItems;
List<String> get items {
_cachedItems ??= _loadFromDisk(); // only computed once
return _cachedItems!;
}
}
Getter vs Regular Method
Both run code when called, but:
- Getter - no parameters, models a property (noun-like:
area,name,isActive); called without(). - Method - can have parameters; models an action (verb-like:
resize(),connect()); called with().
Use a getter when the result feels like reading an attribute value. Use a method when it requires parameters or has significant side effects.
// getter - no (), reads like a property:
print(rect.area);
// method - with ():
print(rect.scaleBy(2.0));
In Immutable / Final Classes
Dart's final keyword on a field makes it read-once (assigned in the constructor). Getters complement final by providing computed, derived properties:
class Person {
final String firstName;
final String lastName;
Person(this.firstName, this.lastName);
String get fullName => '$firstName $lastName'; // computed, not stored
}
Why This Matters in Interviews
Dart/Flutter interviews use getters/setters to test encapsulation and API design. Key points: getters are called without () (making them feel like plain attribute access), setters add validation at assignment, computed properties avoid storing derived data, and a getter without a setter is read-only. The _ private convention and knowing when to use a getter vs a method (no parameters, noun-like = getter) show idiomatic Dart style.
Common Pitfalls
- Forgetting the backing field needs a
_prefix to avoid naming collision with the getter/setter. - Calling a getter with
()- it's a property access, not a method call. - Defining a setter without a matching getter and expecting the property to be readable (you still need a getter or the field to be public).
- Using a getter for something that has significant side effects or takes parameters (use a method instead).
- Forgetting that
finalfields can still have getters but cannot have setters.
References
- Dart getters/setters: https://dart.dev/language/classes#getters-and-setters
- Effective Dart - design: https://dart.dev/effective-dart/design