In Dart, what does a leading underscore make private, and why can another class in the same file read a `_field` it does not own?
answer
- no private keyword
- unit of privacy is the library
- file plus its parts
- friend classes for free
- tests need @visibleForTesting
basics
~20 sA leading underscore makes a name private to its library, meaning the file plus any part files, not to its class. Every declaration in that library can use it, while other libraries, including your own tests, cannot.
solid answer
~40 sDart has no `public`/`private`/`protected` keywords; an identifier starting with `_` is **library-private**, and the compiler enforces it. The unit is the **library**: one file plus its `part` files. So two classes in the same file can read each other's `_fields`, which gives C++-style friend access for free, while any other file cannot see them at all. `_x` declared in two different libraries are two different names, so a subclass in another library cannot override a private member. The docs give the reasons: a simple mechanism, efficient dynamic access, and better tree shaking. Tests live in other libraries, so a member you want to test is made public and annotated `@visibleForTesting` from `package:meta`, which `package:flutter/foundation.dart` re-exports.
code
dart · 18 lines// counter.dart
class Counter {
int _count = 0;
int get value => _count;
}
class CounterAudit {
// Same library, so Counter._count is visible here.
bool isReset(Counter c) => c._count == 0;
}
class Point {
final int _x;
// Dart 3.12+: private field, public argument name `x`.
Point({required this._x});
}
void main() => print(Point(x: 1)._x);go deeper
Recall that a leading underscore means private and that Dart has no private keyword; know that Flutter's _MyWidgetState pattern relies on it.
Explain that the unit is the library, file plus parts, so classes in one file share privates, and how tests cope via @visibleForTesting.
Use library boundaries deliberately: split files to shrink what a class can touch, and keep private types out of public signatures.
Weigh library-level privacy against finer modifiers when setting team rules for file size, friend classes and what tests may reach.
## Privacy is a language rule, not a convention In Dart, a leading underscore is not a naming habit that tools happen to respect: it is part of the language. Any identifier beginning with `_` (a top-level function, variable, class, typedef, extension, or a member of a class, mixin, enum or extension) is **private to its library**. Code in any other library cannot name it, and neither `import` combinators nor prefixes can reach it. There are no access-modifier keywords. The dart.dev libraries page lists why the language chose underscores and library-level privacy: - it is a **straightforward** mechanism with one rule; - it enables an **efficient implementation of dynamic access**, because privacy is visible in the name itself; - it **improves tree shaking**, since the compiler knows no other library can call a private member. ## The unit of privacy is the library A **library** is one Dart file plus any files it pulls in with `part`. Privacy follows that boundary, not the class boundary. Consequences worth knowing: 1. Two classes declared in the same file can read each other's private fields and call each other's private methods. Effective Dart calls this out as a way to get **friend classes**. 2. A `part` file shares the library's private namespace, so `_helper` declared in the main file is usable in the part. 3. A private name declared in library A and a private name spelled the same in library B are **different names**. A subclass in another library that declares `_reset()` does not override its superclass's `_reset()`; it adds an unrelated member. | Where the code lives | Can it use `_count` declared in `counter.dart`? | |---|---| | Another class in `counter.dart` | Yes | | A `part of 'counter.dart'` file | Yes | | `test/counter_test.dart` | No | | Another file in the same package's `lib/` | No | ## Flutter's everyday pattern Flutter code leans on this constantly. A `StatefulWidget` named `CounterPage` usually has its state class declared as `_CounterPageState` in the **same file**: the widget's `createState()` can construct it, and nothing outside the file can. The `library_private_types_in_public_api` lint, in `package:lints`' recommended set that `flutter_lints` includes, flags a private type leaking through a public signature, which is why `createState()` is typically declared to return `State<CounterPage>` rather than `_CounterPageState`. ## Private named parameters (Dart 3.12) Before **Dart 3.12**, a named parameter could not start with an underscore, so initialising a private field from a named parameter needed an initializer list (`Point({required int x}) : _x = x`). Since 3.12 you can write `Point({required this._x})`; the field stays private, while the argument name at the call site is the public `x`, as in `Point(x: 1)`. ## Testing private code Because a test file is its own library, it cannot call `_parse()`. The options are: - test the private logic **through the public API** that uses it (usually the best choice); - make the member public and annotate it `@visibleForTesting` from `package:meta` (re-exported by `package:flutter/foundation.dart`); the analyzer hides it from completion and warns when another package uses it; - move the logic into its own small library under `lib/src/` where it can be public but is not exported. A relative import does **not** make the test part of the same library, and a `show _parse` combinator is not legal.
- In Dart, a class in library B extends a class from library A and declares `_reset()`, which A's class also declares. Is that an override?No. Private names are scoped to their library, so B's `_reset` and A's `_reset` are unrelated names. A's code keeps calling its own `_reset`; B has added a separate member. Overridable hooks must be public, often marked `@protected` from `package:meta`.
- In a Flutter app, why is `createState()` usually declared as returning `State<MyWidget>` rather than `_MyWidgetState`?`createState` is a public method, so returning a private type would expose a name other libraries cannot refer to. The `library_private_types_in_public_api` lint flags exactly that; declaring the public supertype `State<MyWidget>` keeps the signature usable while the state class stays private.
saying these in an interview costs you the question
- Underscore privacy is only a naming convention the compiler ignores
- A _field is private to its class, like Java private
- A test can reach _members by importing the file relatively
- A subclass in another library can override a private method
- Dart has a protected keyword for members subclasses may use