What is the purpose of access control? List the levels.

1.7.1 · L1 · Interview

Predict first

Does this compile? (both in the same file)

struct Account {
    private var balance = 0
}

extension Account {
    func show() -> Int { balance }
}
  • Yes
  • No — balance is private

Mental model. Each level is a fence with a different radius. Start with the smallest fence that still contains the people who need in.

Access control limits who can depend on a declaration — it is how you keep an API small while keeping implementation details free to change.

  • private — the enclosing declaration (and extensions in the same file).
  • fileprivate — the whole file.
  • internal — the module (the default).
  • package — every target in the same SPM package (Swift 5.9).
  • public — any importer, but not overridable/subclassable outside the module.
  • open — importers may subclass and override. Classes only.

Since Swift 4, private is visible to extensions of the same type in the same file. A different file would need fileprivate or wider.

Common traps

  • Making everything public “just in case”. Every public symbol is a compatibility promise you now have to keep.
  • Using fileprivate when private would do. It widens the surface to every declaration in the file, which is rarely needed now that private works across same-file extensions.

They might follow up with

  • Does private work across extensions? Yes, for extensions of the same type in the same file. In another file, no.
  • What about internal and @testable import? That is why test targets can reach internal members — do not make things public just to test them.

Related questions

  • 1.7.2 public vs open? Can a struct be open?
  • 1.7.3 What does package access solve?
  • 1.7.4 What are @usableFromInline and @inlinable in relation to access control?

public vs open? Can a struct be open? →