← → or space · progress saves for Continue on the roadmap
Goal
Hide implementation details so other code cannot change internal state by accident.
Step 1 - Underscore means library-private
class Wallet {
double _balance = 0;
void deposit(double amount) {
if (amount > 0) {
_balance = _balance + amount;
}
}
double get balance => _balance;
}
void main() {
Wallet w = Wallet();
w.deposit(10);
print(w.balance);
}- In Dart, privacy is per library (file), not per class.
- Names starting with
_are visible only inside the same.dartfile.
Step 2 - Why use private fields
- You control how
_balancechanges (only throughdeposit, not random writes). - You can change internals later without breaking callers if the public API stays stable.
Step 3 - Same file, two classes
class Engine {
void start() {
print('vroom');
}
}
class Car {
final Engine _engine = Engine();
void drive() {
_engine.start();
}
}
void main() {
Car c = Car();
c.drive();
}CarusesEngineas an implementation detail;_engineis not part of the public surface ofCarfrom outside this library.
Good habit
- Start public API small: methods and getters callers need, keep fields private when possible.
Practice tasks
- Make a
SafeCounterwith private_count, publicincrement(), and a read-only way to see the count. - Try moving
Walletinto a second file and callw._balancefrommainthere; note the analyzer error and why it appears.