ProgramGuru

Access control and protected mutation

Access control and protected mutation

A register should allow readers to see its attendance count while keeping changes behind an intentional method. Access control states where declarations may be used. It helps maintain an API contract rather than relying on every caller to avoid changing internal fields.

What you’ll learn

  • Expose readable state while restricting its setter.
  • Place validation in controlled state-changing operations.

Access control and protected mutation in the example

  1. Readable state

    A register should allow readers to see its attendance count while keeping changes behind an intentional method.

    Readable state
  2. Controlled operation

    Swift defaults to internal access within a module.

    Controlled operation
  3. Restricted setter

    The method intentionally increments count to one.

    Restricted setter
The method intentionally increments count to one. External code in this example can read count, but cannot directly assign register.count = 50 because the setter is private. Mutating is required because Register is a struct.

How access control and protected mutation works

Swift defaults to internal access within a module. Private and fileprivate restrict implementation visibility; public exposes appropriate API across modules, while open also permits relevant subclassing and overriding outside the defining module. A private(set) property can be readable more widely while keeping its setter private.

Work through access control and protected mutation

Save this complete program as main.swift and run it with the Swift toolchain. No separate input file is needed.

Swift · complete program

struct Register {
  private(set) var count = 0
  mutating func recordArrival() { count += 1 }
}
var register = Register()
register.recordArrival()
print(register.count)

Expected output

1

Follow the execution

The method intentionally increments count to one. External code in this example can read count, but cannot directly assign register.count = 50 because the setter is private. Mutating is required because Register is a struct.

Try this program in the Swift compiler. Paste the complete source above.

Practice: Access control and protected mutation

Your task: Where should you add validation if arrivals have a maximum count?

Swift · complete program

struct Register {
  private(set) var count = 0
  mutating func recordArrival() { count += 1 }
}
var register = Register()
register.recordArrival()
print(register.count)

Worked answer

Put it in the operation that changes count, and define a result for reaching the limit. A restricted setter makes that centralized policy harder to bypass through ordinary callers.

Centralize the permitted updates

Access control is a source-level API rule, not encryption or a protection against someone controlling the running process. Package access also exists for declarations shared within a Swift package; choose boundaries appropriate to the project structure.

Check your decision

Where should you add validation if arrivals have a maximum count?
Choose one answer. You can try again.

Answer and explanation

Put it in the operation that changes count, and define a result for reaching the limit.

Put it in the operation that changes count, and define a result for reaching the limit. A restricted setter makes that centralized policy harder to bypass through ordinary callers.

Centralize the permitted updates

Put it in the operation that changes count, and define a result for reaching the limit. A restricted setter makes that centralized policy harder to bypass through ordinary callers. Access control is a source-level API rule, not encryption or a protection against someone controlling the running process.

Further reading: official Swift language guide.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: ARC, weak references and ownership cycles →