Skip to content
TaeyoungKim.dev

Dart private underscore scope: Why another class can read it but an import cannot

AppWritten 3 min readTaeyoungKim
LinkedInX

Rename a field to _code, expecting only Badge itself to read it. Another class in the same file reads it successfully, but an importing file gets an analyzer error. The rule is consistent once you identify the boundary: a leading underscore hides a Dart name outside its library, not outside its class.

Is Dart underscore privacy class-scoped?

No. A Dart library is a unit of visibility. Usually one Dart file is one library, and a name beginning with _ is visible only within that library. The Dart libraries guide describes library-private identifiers.

The diagram follows _code across the library boundary. BadgeLabel in badge.dart can read it and expose a selected suffix; main.dart, which imports that library, cannot read the field directly.

Why can another class in the same file read it?

Put two unrelated classes in badge.dart. BadgeLabel is not a subclass or a method of Badge, yet it can read _code because both classes belong to the same library:

dart
// badge.dart
class Badge {
  Badge(this._code);

  final String _code;
}

class BadgeLabel {
  static String suffix(Badge badge) =>
      badge._code.substring(badge._code.length - 2);
}

Reading Dart's _ as though it were Java's class-level private would predict the wrong result here.

Why does an importing file fail?

Place this beside badge.dart:

dart
// main.dart
import 'badge.dart';

void main() {
  final badge = Badge('A42');
  print(BadgeLabel.suffix(badge)); // 42
  // print(badge._code);           // Uncomment for an analyzer error.
}

dart run main.dart prints 42. Uncomment the final line and run dart analyze main.dart; the analyzer reports undefined_getter for _code. The import exposes public Badge and BadgeLabel, not another library's private member.

The public suffix() method returning 42 is consistent with this rule: code inside the library reads _code, then deliberately returns a chosen value to the outside.

What if several files belong to one library?

A normal import brings in a different library. A file included with part belongs to the original library, so code in that part can access its private names. Count libraries, not files or directories:

Code locationDirect access to Badge._code
Another class inside badge.dartAllowed
main.dart importing badge.dartNot allowed
A file included as a part of badge.dartAllowed

This is an explanation of the visibility boundary, not a reason to split new code into part files unnecessarily.

Does a private field secure a secret?

An underscore controls access in Dart source code; it is not encryption or secret storage. The public helper already exposes two characters intentionally. Naming a client-side token _token does not keep that token secret from someone who can inspect the client. Expose only necessary operations and keep actual secrets out of client code.

Key takeaways

Dart's _ protects a name at the library boundary. Another class in the same library can read it, while a normal importing file cannot. A part can share that boundary. Visibility rules and secure storage are separate concerns.

Author

TaeyoungKim

Connecting technical foundations with implementation, verification, and production decisions.

#Dart#Dart private#Underscore#Dart library#import#Encapsulation

Read next