skip to content

Libraries & Imports

Every Dart file is a library whose underscore names are private to it; import with prefixes, show and hide, re-export with export, and load lazily with deferred as. Interviewers probe privacy.

part ofDartoverview, primer and where to startread it →
on this pageshow

explore

questions

6

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?

level: middleimportance: must knowfreq 60%

answer

  1. no private keyword
  2. unit of privacy is the library
  3. file plus its parts
  4. friend classes for free
  5. tests need @visibleForTesting

basics

~20 s

A 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 s

Dart 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
dart
// 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

for a junior

Recall that a leading underscore means private and that Dart has no private keyword; know that Flutter's _MyWidgetState pattern relies on it.

for a middle

Explain that the unit is the library, file plus parts, so classes in one file share privates, and how tests cope via @visibleForTesting.

for a senior

Use library boundaries deliberately: split files to shrink what a class can touch, and keep private types out of public signatures.

for a principal

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
open as a page

In Dart, when two imported libraries both declare a class named `Element`, how do `import ... as`, `show` and `hide` resolve the clash?

level: juniorimportance: should knowfreq 45%

basics

~20 s

Bind one library to a prefix with as, so its names are reached as lib2.Element, or narrow an import with show (only the listed names) or hide (everything except the listed names). Unresolved clashes are errors only where the name is used.

open as a page

In Dart, what do `part` and `part of` do, how does a part differ from a separate library, and when is a `library` directive needed?

level: middleimportance: should knowfreq 30%

basics

~20 s

part splits one library across files: a part file shares its owner's imports, namespace and private names. The part of directive should name its owner by URI string. A library directive is now only needed to attach library-level docs or annotations.

open as a page

When splitting a Dart utilities package into a public API and `lib/src` internals, how do `export ... show` and `lib/src` decide what consumers depend on?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Put implementation in lib/src and a main library at lib/<package>.dart that re-exports chosen names with export ... show. Consumers import the main file; lib/src is private by convention only, so anything exported is the real public API.

open as a page

In a Dart package, why can importing one file as both `package:my_pkg/src/cache.dart` and `../lib/src/cache.dart` break type checks and duplicate a singleton?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Dart identifies a library by its URI, so a package: import and a relative path into lib load the same file twice as two unrelated libraries, with separate classes and separate top-level variables. Type tests fail and singletons exist twice.

open as a page

In Dart, what does `import ... deferred as` do, and what restrictions apply to a deferred library before and after `loadLibrary()` completes?

level: middleimportance: nice to knowfreq 15%

basics

~20 s

deferred as lets a web app download a library on demand: you await prefix.loadLibrary() before touching its members. Its types cannot appear in the importing file, its constants are not constants there, and the dart tool supports deferral only for web targets.

open as a page