Menu
Coddy logo textTech

Public vs Private Members

Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 30 of 110.

Encapsulation is one of the core principles of object-oriented programming. It's about controlling access to a class's internal data, deciding what should be visible to the outside world and what should remain hidden.

In Dart, class members (fields and methods) are public by default. This means any code can access them directly:

class BankAccount {
  String owner;
  double balance;
  
  BankAccount(this.owner, this.balance);
}

var account = BankAccount('Alice', 1000);
account.balance = -500;  // Anyone can modify this directly!

This is problematic. Nothing prevents setting an invalid balance.

To protect internal data, Dart uses private members. A member becomes private when its name starts with an underscore _:

class BankAccount {
  String owner;
  double _balance;  // Private - starts with underscore
  
  BankAccount(this.owner, this._balance);
  
  double get balance => _balance;  // Controlled access
}

Now _balance cannot be accessed directly from outside the library where the class is defined. External code must use the public getter instead. This lets you control how data is read and modified, ensuring your objects always remain in a valid state.

challenge icon

Challenge

Easy

Let's build a simple password manager that demonstrates the difference between public and private members. You'll see how the underscore prefix protects sensitive data from being accessed directly from outside the class's library.

You'll create two files to organize your code:

  • credential.dart: Define a Credential class that stores login information for a website. The class should have:
    • A public String website - it's fine for anyone to see which website this is for
    • A public String username - the username can be visible
    • A private String _password - the actual password must be protected
    • A constructor that takes all three values
    • A public getter password that returns the private _password (controlled access)
    • A method getMaskedPassword() that returns the password with all characters replaced by asterisks * (same length as the actual password)
    • A method displayCredential() that prints the credential information safely (showing the masked password, not the real one)
  • main.dart: Import your credential class and demonstrate how encapsulation protects the password:
    • Create a credential for website 'github.com', username 'dev_user', and password 'secret123'
    • Create another credential for website 'email.com', username 'john_doe', and password 'myP@ss'
    • For each credential, call displayCredential(), then print Actual password length: [length] using the public getter to access the password's length

The displayCredential() method should print in this format:

--- Credential ---
Website: [website]
Username: [username]
Password: [maskedPassword]

Expected output:

--- Credential ---
Website: github.com
Username: dev_user
Password: *********
Actual password length: 9
--- Credential ---
Website: email.com
Username: john_doe
Password: ******
Actual password length: 6

Cheat sheet

Encapsulation controls access to a class's internal data by deciding what should be visible and what should remain hidden.

In Dart, class members are public by default:

class BankAccount {
  String owner;
  double balance;  // Public - can be accessed directly
  
  BankAccount(this.owner, this.balance);
}

var account = BankAccount('Alice', 1000);
account.balance = -500;  // Direct modification allowed

To protect internal data, use private members by prefixing the name with an underscore _:

class BankAccount {
  String owner;
  double _balance;  // Private - starts with underscore
  
  BankAccount(this.owner, this._balance);
  
  double get balance => _balance;  // Controlled access via getter
}

Private members cannot be accessed directly from outside the library where the class is defined. Use public getters and methods to provide controlled access to private data, ensuring objects remain in a valid state.

Try it yourself

import 'credential.dart';

void main() {
  // TODO: Create a credential for github.com
  // website: 'github.com', username: 'dev_user', password: 'secret123'
  
  // TODO: Call displayCredential() on the first credential
  
  // TODO: Print the actual password length using the public getter
  // Format: "Actual password length: [length]"
  
  // TODO: Create a credential for email.com
  // website: 'email.com', username: 'john_doe', password: 'myP@ss'
  
  // TODO: Call displayCredential() on the second credential
  
  // TODO: Print the actual password length using the public getter
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming