What are Getters and Setters?
Getters and setters are special methods that allow you to read and write the value of a property. They look like property accesses to the caller but execute method logic behind the scenes. This is how Dart implements encapsulation — hiding internal implementation details while providing controlled access.
Defining a Getter
A getter uses the get keyword and has no parameter list:
class Circle {
double radius;
Circle(this.radius);
// Getter: computed from radius
double get diameter => radius * 2;
double get area => 3.14159 * radius * radius;
double get circumference => 2 * 3.14159 * radius;
}
void main() {
var c = Circle(5.0);
print(c.diameter); // 10.0
print(c.area.toStringAsFixed(2)); // 78.54
print(c.circumference.toStringAsFixed(2)); // 31.42
}
Defining a Setter
A setter uses the set keyword and accepts exactly one parameter. It allows validation before assigning a value:
class Temperature {
double _celsius = 0.0; // private backing field
// Getter
double get celsius => _celsius;
// Setter — validates before assigning
set celsius(double value) {
if (value < -273.15) {
throw ArgumentError(''Temperature below absolute zero: $value'');
}
_celsius = value;
}
// Computed getters for other units
double get fahrenheit => _celsius * 9 / 5 + 32;
double get kelvin => _celsius + 273.15;
}
void main() {
var temp = Temperature();
temp.celsius = 100; // uses setter
print(temp.fahrenheit); // 212.0
print(temp.kelvin); // 373.15
try {
temp.celsius = -300; // throws ArgumentError
} on ArgumentError catch (e) {
print(e.message);
}
}
Output:212.0
373.15
Temperature below absolute zero: -300.0
Computed Properties
Getters excel at computed properties — values derived from other fields. They update automatically when the underlying data changes:
class ShoppingCart {
final List<double> _prices = [];
void addItem(double price) => _prices.add(price);
void removeItem(double price) => _prices.remove(price);
double get subtotal => _prices.fold(0.0, (sum, p) => sum + p);
double get tax => subtotal * 0.08;
double get total => subtotal + tax;
int get itemCount => _prices.length;
bool get isEmpty => _prices.isEmpty;
}
void main() {
var cart = ShoppingCart();
cart.addItem(29.99);
cart.addItem(14.99);
cart.addItem(4.99);
print(''Items: \$${cart.itemCount}'');
print(''Subtotal: \$\$${cart.subtotal.toStringAsFixed(2)}'');
print(''Tax: \$\$${cart.tax.toStringAsFixed(2)}'');
print(''Total: \$\$${cart.total.toStringAsFixed(2)}'');
}
Encapsulation with Private Fields
In Dart, fields starting with _ are private to the library file. Getters and setters provide controlled public access:
class BankAccount {
String _owner;
double _balance;
BankAccount(this._owner, double initialBalance)
: _balance = initialBalance >= 0 ? initialBalance : 0;
String get owner => _owner;
double get balance => _balance; // read-only — no setter
void deposit(double amount) {
if (amount <= 0) throw ArgumentError(''Deposit must be positive'');
_balance += amount;
}
void withdraw(double amount) {
if (amount <= 0) throw ArgumentError(''Withdrawal must be positive'');
if (amount > _balance) throw StateError(''Insufficient funds'');
_balance -= amount;
}
}
void main() {
var account = BankAccount(''Alice'', 1000.0);
print(account.balance); // 1000.0
account.deposit(500);
print(account.balance); // 1500.0
// account._balance = 999999; // ERROR: private field
}
Full Example: Product Inventory
class Product {
final String id;
String _name;
double _price;
int _stock;
Product({required this.id, required String name, required double price, int stock = 0})
: _name = name, _price = price, _stock = stock;
String get name => _name;
set name(String value) {
if (value.trim().isEmpty) throw ArgumentError(''Name cannot be blank'');
_name = value.trim();
}
double get price => _price;
set price(double value) {
if (value < 0) throw ArgumentError(''Price cannot be negative'');
_price = value;
}
int get stock => _stock;
bool get inStock => _stock > 0;
bool get lowStock => _stock > 0 && _stock <= 5;
void restock(int units) {
if (units <= 0) throw ArgumentError(''Units must be positive'');
_stock += units;
}
bool sell(int units) {
if (units > _stock) return false;
_stock -= units;
return true;
}
@override
String toString() => ''Product($id, $_name, \$\$${_price.toStringAsFixed(2)}, stock=$_stock)'';
}
void main() {
var p = Product(id: ''P001'', name: ''Dart Book'', price: 39.99, stock: 10);
print(p);
p.sell(3);
print(''In stock: \$${p.inStock}, Low stock: \$${p.lowStock}'');
p.price = 34.99;
print(p);
}
Output:Product(P001, Dart Book, $39.99, stock=10)
In stock: true, Low stock: false
Product(P001, Dart Book, $34.99, stock=7)
Exercise
- Create a
Rectangle class with private _width and _height fields, validated setters (must be positive), and getters for area, perimeter, and isSquare.
- Create a
Password class with a setter that requires at least 8 characters, one digit, and one uppercase letter. The getter should return the hashed version (simulate with reversed string).
Quiz
1. What keyword defines a getter in Dart?
- A) property
- B) get ✅
- C) read
- D) accessor
2. Can a Dart getter have parameters?
- A) Yes, any number
- B) Yes, exactly one
- C) No, getters take no parameters ✅
- D) Only optional parameters
3. What is the main benefit of a setter over direct field assignment?
- A) Faster performance
- B) Validation and encapsulation — logic runs before the value is stored ✅
- C) Automatic type conversion
- D) Thread safety
Summary
Getters (get) and setters (set) provide controlled property access in Dart. Define getters for computed properties that derive from other fields. Use setters to validate input before assigning to private backing fields. Fields prefixed with _ are private to the library file, enforcing encapsulation. Callers access getters and setters exactly like regular fields — the logic is transparent.