Macros vs property wrappers vs result builders — one sentence each.

1.10.3 · L3 · Interview

Mental model. Wrapper = runtime storage. Builder = compile-time list. Macro = compile-time code generation. Three different layers.

Property wrapper — wraps storage and routes get/set through wrappedValue at runtime.

Result builder — compiles a block of statements into one expression, building a DSL (@ViewBuilder).

Macro — generates or transforms source/AST at compile time (@Observable, #Preview, #expect). It can replace boilerplate that used to need a wrapper, at the cost of toolchain complexity and slower builds.

Common traps

  • Calling @Observable a property wrapper. It is a macro — the most common version of this trick question.
  • Using a macro where a wrapper is enough. Macros expand into code you must debug; wrappers are simpler and better understood by tooling.
  • Expecting macros to run at runtime. They do not exist at runtime; they only produce code.

They might follow up with

  • When would you avoid macros? When the team's toolchain is not uniform, when debugging transparency matters, or when a small wrapper or protocol would do.
  • What is a freestanding macro vs an attached macro? Freestanding is called like #foo; attached decorates a declaration like @foo.

Related questions

  • 1.6.3 What is a property wrapper? Can you write a custom one?
  • 1.6.4 What is projectedValue? Give a real example.
  • 1.5.8 What is a result builder (@ViewBuilder, @CommandsBuilder)?

← What does Sendable mean for a Swift type you write?   What is ABI stability vs source compatibility vs module stability? →