Library-Level Privacy
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 32 of 110.
In Dart, privacy is enforced at the library level, not the class level. This is a key distinction from languages like Java or C++. A library in Dart is typically a single file, or multiple files connected with part directives.
Private members (those starting with _) are accessible anywhere within the same library, even from other classes:
// Both classes in the same file (same library)
class Engine {
int _horsepower = 200; // Private to this library
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // Accessible! Same library
}
}However, when you import a class from a different file, its private members become truly hidden:
// file: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// file: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // Error! Not accessible
print(engine.power); // Works - using public getter
}This library-level privacy means classes in the same file can collaborate closely while still hiding implementation details from external code. It's a deliberate design choice that encourages organizing related classes together in the same library.
Challenge
EasyLet's build a team collaboration system that demonstrates how library-level privacy works in Dart. You'll see how classes in the same file can access each other's private members, while code in separate files cannot.
You'll organize your code into two files:
team.dart: This file will contain two classes that work closely together in the same library:- A
Memberclass with a publicString nameand a privateint _performanceScoreinitialized to50. Include a constructor that takes the name, and a public getterperformanceScorethat returns the private score. - A
TeamLeadclass in the same file that can accessMember's private field directly (because they're in the same library). This class should have a publicString name, a constructor that takes the name, and a methodevaluateMember(Member member)that directly accessesmember._performanceScore, adds10to it, and prints[leadName] boosted [memberName]'s score to [newScore].
- A
main.dart: Import your team file and demonstrate the difference in access:- Create a
Membernamed'Alice' - Create a
TeamLeadnamed'Bob' - Print
Initial score: [score]using the public getter on Alice - Have Bob evaluate Alice using
evaluateMember - Print
Updated score: [score]using the public getter - Print
Direct access from main: Not allowed(this reminds us thatmain.dartcannot access_performanceScoredirectly since it's in a different library)
- Create a
The key insight here is that TeamLead can directly read and modify Member's private _performanceScore because both classes live in the same file (same library). However, code in main.dart must use the public getter because it's in a different library.
Expected output:
Initial score: 50
Bob boosted Alice's score to 60
Updated score: 60
Direct access from main: Not allowedCheat sheet
In Dart, privacy is enforced at the library level, not the class level. A library is typically a single file, or multiple files connected with part directives.
Private members start with an underscore (_) and are accessible anywhere within the same library, even from other classes:
// Both classes in the same file (same library)
class Engine {
int _horsepower = 200; // Private to this library
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // Accessible! Same library
}
}When you import a class from a different file, its private members become hidden:
// file: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// file: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // Error! Not accessible
print(engine.power); // Works - using public getter
}This design encourages organizing related classes together in the same library, allowing them to collaborate closely while hiding implementation details from external code.
Try it yourself
import 'team.dart';
void main() {
// TODO: Create a Member named 'Alice'
// TODO: Create a TeamLead named 'Bob'
// TODO: Print "Initial score: [score]" using the public getter on Alice
// TODO: Have Bob evaluate Alice using evaluateMember
// TODO: Print "Updated score: [score]" using the public getter
// TODO: Print "Direct access from main: Not allowed"
// Note: We cannot access alice._performanceScore here because
// main.dart is in a different library than team.dart
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor