I Thought This Was Private… Until Dart Surprised Me

Table of contents

I was working on a simple budgeting feature for a finance app when something unexpected happened something that made me question everything I knew about encapsulation in Dart.
Let me walk you through the mistake that taught me something incredibly valuable.
The Real-World Setup: A Budgeting App
Imagine you’re building a personal finance app. Nothing too fancy just a way for users to track their account balances.
You decide to create a BankAccount
class with a private _balance
field, because hey, you don’t want other parts of your app messing with the internal state directly. So, you write this main.dart
file:
void main() {
BankAccount account = BankAccount();
account.deposit(100);
// Wait, this works?
print("Balance is: ${account._balance}");
}
// BankAccount class
class BankAccount {
int _balance = 0;
void deposit(int amount) {
_balance += amount;
}
int getBalance() {
return _balance;
}
}
And guess what? It prints:
Balance is: 100
Wait… I Thought That Was Private?
At first, I was confused. I clearly prefixed _balance
with an underscore. In almost every language I’ve used Java, C++, even TypeScript that should restrict access to that variable from outside the class.
Yet Dart just… let me access it.
Had I misunderstood how encapsulation works in Dart?
The Investigation Begins
After a bit of digging (and some help from the Dart documentation), I stumbled on a key sentence:
In Dart, identifiers that start with an underscore (_) are private to the library, not the class.
Boom. There it was.
That single sentence flipped my understanding upside down. I wasn’t breaking any rules I was just dealing with a language that thinks about privacy in a different way.
What Does “Library-Private” Mean?
In Dart, privacy is not scoped to the class, but to the library and a library in Dart usually means a single file (unless explicitly split with part
/part of
).
So, in my example, both main()
and BankAccount
live in the same file. That means Dart treats them as part of the same library, so accessing _balance
is allowed.
Let’s Split the Files
To test this, I moved the BankAccount
class to a separate file.
// bank_account.dart
class BankAccount {
int _balance = 0;
void deposit(int amount) {
_balance += amount;
}
int getBalance() {
return _balance;
}
}
Then in main.dart
:
import 'bank_account.dart';
void main() {
BankAccount account = BankAccount();
account.deposit(100);
print("Balance is: ${account._balance}"); // ❌ ERROR!
}
Boom! Dart now throws a compile-time error:
Error: The getter '_balance' isn't defined for the class 'BankAccount'.
The Takeaway: Dart’s Encapsulation Is Different
So, here’s what I learned and what you should take away from this:
In Dart, prefixing with
_
makes a variable or method private to the file (library), not just the class.If your classes and main logic are in the same file, Dart won’t enforce class-level encapsulation.
To achieve stronger encapsulation, structure your code in multiple files or use
getters
andsetters
to manage controlled access.
How Other Languages Do It (Quick Comparison)
Java:
private
,protected
,public
keywords control access at class/package levelC++: Class-level privacy via
private:
/protected:
blocksPython: Name mangling (
__var
) gives soft privacyDart: Underscore
_
= library-level privacy
Dart’s choice is intentional. It promotes module-based design, encouraging developers to treat files as cohesive units of logic, similar to libraries in larger ecosystems.
Real-World Best Practices
If you’re building something real and want to keep internals safe:
Split your classes into separate Dart files.
Use public
getters
andsetters
to expose or modify state safely.Stick to the Single Responsibility Principle don’t overload one file with too many concerns.
Wrapping Up
What started as a simple budgeting feature turned into a lesson in how Dart thinks differently about encapsulation. And honestly? I’m glad I stumbled onto this early.
Knowing how Dart’s privacy model works will help you avoid subtle bugs, write cleaner code, and structure your apps better especially in large Flutter projects.
What About You?
Have you ever been surprised by a language’s encapsulation model? Hit me up if you’ve faced this in Dart (or any other language). Would love to hear your story too.
Subscribe to my newsletter
Read articles from Md. Al - Amin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Md. Al - Amin
Md. Al - Amin
Experienced Android Developer with a demonstrated history of working for the IT industry. Skilled in JAVA, Dart, Flutter, and Teamwork. Strong Application Development professional with a Bachelor's degree focused in Computer Science & Engineering from Daffodil International University-DIU.