freenode
Languages & Toolchains

Swift pitch proposes @called(once) for one-shot function values

The attribute would let the compiler enforce at-most-once calls and reason about closure captures alongside non-copyable types.

Swift contributor xedin has pitched a @called(once) attribute to mark function values that may be invoked at most once. The goal is twofold: diagnose repeated calls, and give the compiler enough information about closure captures and lifetimes to work more smoothly with non-copyable types.

The attribute would attach to function values, not declarations. Each time an expression forms such a closure, the result is a fresh value that can be called only once, much like a non-copyable holder that consumes itself on use. Slava Pestov compared the model to a simple non-copyable wrapper whose only operation is a consuming call.

On the Swift forums, several engineers described the pitch as packing three related rules into one annotation: the closure type becomes non-copyable, calling it is consuming, and parameters default to consuming ownership. xedin agreed those three pieces cover the intended semantics, including the ability to consume captures inside the body the way consuming methods already consume stored properties. Others floated a stricter “exactly once” variant that would trap if the value is never called, which could help APIs such as continuations, while keeping “at most once” for cases like cancellation-aware task spawning.

Not everyone favored a new compiler feature. One alternative sketched a macro that swaps the implementation for a fatal-error stub after the first call. Critics of that approach noted that macros would not plug into flow-sensitive checking, sending, or non-copyable analysis the same way a first-class attribute would. Separate concern focused on implicit self-capture: Task initializers already rely on it, and some worry that wider adoption of call-once APIs could spread the same confusing, flow-sensitive diagnostics rather than leave room to revisit those defaults.

The idea remains a pitch in the Swift Evolution process.