# \[Pitch #2\] Called-once function types

**URL:** <https://forums.swift.org/t/pitch-2-called-once-function-types/90515>\
**Category:** Pitches\
**Created:** [November 5, 2026, 10:01pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515 "2026-11-05T22:01:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [November 5, 2026, 10:01pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/1 "2026-11-05T22:01:00Z")

</div>

Hello Swift Evolution!

This is the second pitch for a language feature that lets you annotate function types as executing exactly once or at most once:

```swift
func callOnce(_ c: @once () -> Void) {
  c()
  c() // error: 'c' is consumed more than once
}

```

Read the full proposal in [this pull request](https://github.com/swiftlang/swift-evolution/pull/3429).

The motivation for this feature is to give the compiler enough information to let closures passed to certain APIs consume values of noncopyable types and re-send values of non-`Sendable` types. Today, code that attempts this is rejected, because it would not be safe if the closure ran more than once.

Since the [first pitch](https://forums.swift.org/t/pitch-introduce-a-way-to-annotate-functions-that-are-called-at-most-once/89088), we have updated the proposal to incorporate feedback from that thread. The most significant change is the addition of the `@once` attribute, which models closures that execute _exactly_ once rather than at most once. Exactly-once semantics are much more common in APIs than at-most-once semantics and exactly-once closures could enable future features, such as user-defined linear types. Introducing `@once` now spares the ecosystem a second costly migration later.

Other changes include:

- Renamed the attribute for functions that may be called at most once from `@called(once)` to `@callable(once)`.
- Added the compiler-internal `Deinitable` protocol to model the constraints of `@once` types.
- Added `withoutActuallyDeiniting(_:do:)` to convert `@once` functions to `@callable(once)` functions.
- Narrowed `sending` inference for non-escaping closures to the captures that the closure body sends.
- Specified the rules for overrides, top-level protocol witness mismatches, overloads that differ only in execution semantics, and storage of these function values.
- Designed C, C++, and Objective-C interoperability, including dynamic enforcement for imported `called_once` parameters.
- Described the plan for adopting these attributes in the standard library.

See the Alternatives considered and Future directions sections for discussion of many of the topics from the first pitch thread.

Please let us know what you think, and thanks for your time!

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [November 5, 2026, 11:34pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/2 "2026-11-05T23:34:52Z")

</div>

Really great proposal, so many questions I had at the start were comprehensively answered by the end. I even more-or-less came around to the naming 🤣

The only major question I was left with was the idea that `@once` closures can escape. As discussed in other threads, `~Deinitable` isn't linear on its own; `~Deinitable & ~Escapable` is linear. It seems to me that (within the proposed syntax\*\*), we must make an arbitrary choice as to which one of those two possibilities to pick for `@once`, with `~Deinitable` (as proposed) providing less safety but somewhat more flexibility than `~Deinitable & ~Escapable`.

The proposal text says

> A `@once` value is not called if:
> 
> - ...
> - ownership of the value is transferred to a context that is never destroyed, such as a closure that is kept alive by a reference cycle or by a global variable.

The proposal expressly excludes globals of `~Deinitable` types and a non-`@once` closure can't capture a `@once` closure (because that would store a `~Deinitable` type in a `Deinitable` one). So I guess the only way to achieve this is to wrap the `@once` closure with `withoutActuallyDeiniting`.

Speaking of which, the design of `withoutActuallyDeiniting` is strange to me — given that the argument is allowed to escape, the `with` form makes little sense (particularly since it won't work with async closures). But then it's also this escaping that causes the above weaknesses in `@once`. It seems like maybe we should _keep_ the `with` form (with async overload) and make the resultant closure _non-_ escaping (noting that the programmer can still use `withoutActuallyEscaping` to break out of that situation).

If we allow escaping, including by changing the function to simply return the wrapped closure rather than keeping the `with` form, then I think it should at least be marked & named as being unsafe, in that the `@once` closure may be being used to uphold an arbitrary safety guarantee, and this function allows anyone to break that guarantee, whatever it may be.

* * *

\*\* that is, if instead of `@once` we wrote `@Nondeinitable @Noncopyable`, we could allow both these options. I am generally in agreement with the proposal that a single attribute is better, though.

---

<div class="post-metadata">

**Author:** ![aviva](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aviva/32/44327_2.png) [@aviva](https://forums.swift.org/u/aviva)\
**Post date:** [November 5, 2026, 11:46pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/3 "2026-11-05T23:46:03Z")

</div>

> [@KeithBauerANZ](#):
>
> The only major question I was left with was the idea that `@once` closures can escape. As discussed in other threads, `~Deinitable` isn't linear on its own; `~Deinitable & ~Escapable` is linear. It seems to me that (within the proposed syntax\*\*), we must make an arbitrary choice as to which one of those two possibilities to pick for `@once`, with `~Deinitable` (as proposed) providing less safety but somewhat more flexibility than `~Deinitable & ~Escapable`.

Are you factoring in that function parameters are non escaping by default? If the only annotation you write on a function parameter is `@once`, it is linear\[1\] afaik.

> Like ordinary function types in parameter positions, `@once` and `@callable(once)` types are not escaping unless the `@escaping` attribute is specified.

* * *

1. for certain definitions of linear...

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [November 6, 2026, 12:04am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/4 "2026-11-06T00:04:04Z")

</div>

> [@KeithBauerANZ](#):
>
> The only major question I was left with was the idea that `@once` closures can escape. As discussed in other threads, `~Deinitable` isn't linear on its own; `~Deinitable & ~Escapable` is linear.

I disagree, linear logic does not have any notion of "escapability": [Linear logic - Wikipedia](https://en.wikipedia.org/wiki/Linear_logic)

To put it another way, what invariants are broken by allowing a `~Deinitable & Escapable` function type?

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [November 6, 2026, 12:05am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/5 "2026-11-06T00:05:40Z")

</div>

Looks from the examples like the `@escaping`-ness of the `withoutActuallyDeiniting` parameter matches its argument, rather than having that `@escaping` removed.

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [November 6, 2026, 1:06am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/6 "2026-11-06T01:06:51Z")

</div>

I think that this thread says everything about the interaction of `~Deinitable` with `Escapable` that I want to say, and better than I can: [How might linear types work in swift?](https://forums.swift.org/t/how-might-linear-types-work-in-swift/89215). But basically if we allow any "safe" language or library construct that allows a `~Deinitable` type to be leaked, or stored in a `~Deinitable` type, then we no longer have linear types. That's relevant because this proposal is proposing `withoutActuallyDeiniting`, which does (as proposed) allow that to happen. As in my original reply, restricting the `Deinitable` wrapper created by `withoutActuallyDeiniting` to be `~Escapable` closes that hole.

In attempting to compose this reply, I noticed that this proposal needs to ban `@discardableResult` for `~Deinitable` types.

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [November 6, 2026, 1:21am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/7 "2026-11-06T01:21:27Z")

</div>

> [@KeithBauerANZ](#):
>
> But basically if we allow any "safe" language or library construct that allows a `~Deinitable` type to be leaked, or stored in a `~Deinitable` type, then we no longer have linear types.

But you can already leak such a type even if it doesn’t escape:

```swift
let x = createNonDeinitableValue()
while true {}
// nothing discards x

```

> [@KeithBauerANZ](#):
>
> In attempting to compose this reply, I noticed that this proposal needs to ban `@discardableResult` for `~Deinitable` types.

This would be a nice ergonomic improvement, but I imagine the move-only checker would catch such a call at the SIL level.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [November 6, 2026, 1:23am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/8 "2026-11-06T01:23:00Z")

</div>

What led you to pick such different names for these two attributes? Naively I would expect them to read pretty similarly. (`@called(once)` or `@called(exactlyOnce)` and `@called(atMostOnce)`, for example).

Overall, I think this pitch is pretty great, but the asymmetry really sticks out to me.

I do see a little text in alternatives considered about this, but I'm not sure "the `@called(exactlyOnce)` spelling is significantly more verbose than `@once`, though, which is undesirable for such a common attribute." really holds water. It's really not verbose, compared to common Swift APIs and attributes, and that rationale directly contradicts the rationale offered for defining _both_ attributes. I'm less looking for iron-clad logic, and more for "can you expand on the thinking that led you here?"

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [November 6, 2026, 2:01am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/9 "2026-11-06T02:01:55Z")

</div>

> [@Slava\_Pestov](#):
>
> But you can already leak such a type even if it doesn’t escape:
> 
> ```swift
> let x = createNonDeinitableValue()
> while true {}
> // nothing discards x
> 
> ```

This is undeniably true, but I still don't find it convincing 🙂

I think the difference in my mind is along the lines of, we tied the lifetime of `x` to the lexical scope, and the lexical scope still exists (until the app is killed), so x is still "in use", so not deiniting it is correct. And if someone later adds a `break` statement to that loop, the code will be correct. Whereas if we leak it entirely, we've lost track of a value we promised to deinit, and can no longer fulfill that promise in any circumstance.

Fully aware this is more of an emotional argument than a logical one. Though I do think the "will a future maintainer of the code automatically uphold safety guarantees they don't fully understand" angle is important.

---

<div class="post-metadata">

**Author:** ![j-f1](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/j-f1/32/12287_2.png) [@j-f1](https://forums.swift.org/u/j-f1)\
**Post date:** [November 6, 2026, 2:28am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/10 "2026-11-06T02:28:05Z")

</div>

Can you include the declarations of the `Copyable`, `Escapable`, and `Deinitable` protocols in the pitch? It wasn’t clear to me which ones inherit from each other now.

Did you consider importing nullable `called_once` blocks as `@callable(once)` types so that they’re allowed to be optional? (This could always be reversed when `Optional: ~Deinitable` in the future).

Similarly, can you include a discussion of the source compatibility impacts of moving from `@once` to `@callable(once)` in an API (or vice versa)?

Do you envision updating any protocols in the standard library to use called-once function types?

In the “ Only offer `@once` without `@callable(once)`” section, you say “this would forfeit the ability to improve noncopyable and non-`Sendable` type ergonomics for many widely used APIs.” Could you elaborate on the kinds of APIs that would need these semantics?

The spelling of `withoutActuallyDeiniting` feels very awkward to me. Have you considered alternative spellings? I agree with Keith that making it a `with`-style function seems unnecessary. Some names to consider: `guaranteeCall(to:)`, `guaranteeConsumption(of:)`.

> In the future, the author of a C or Objective-C API could be given a way to assert that the implementation honors `called_once`, allowing Swift to pass arguments to it without incurring overhead from dynamic checks.

This is also an issue with `NS_NOESCAPE` (where an escapable closure is constructed anyway). It would be really great to have some sort of `NS_I_PROMISE_TO_FOLLOW_CLOSURE_RULES` attribute that eliminates both of these sources of overhead, for cases when you need help from C or Objective-C to provide scoped access to a resource.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [November 6, 2026, 3:21am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/11 "2026-11-06T03:21:12Z")

</div>

So, the thing is, if you want to tie the lifetime of a value to a scope, that’s what `~Escapable` is for. I don’t think anybody is arguing that it’s okay for a non-escaping exactly-once function to not have been called by the end of its scope. If we ever find a corner case in the language that allows that, we should close it.

But I don’t think it makes any sense to use this argument to tie ourselves in knots and say that escaping exactly-once functions are logically Wrong unless we combine them with some completely unworkable system of proving that call sites will always be reached. Leaks of the kind you’re worried about are, basically, combinations of latent local obligations that happen to be dynamically impossible to satisfy. The difference between possibility and impossibility in these cases is essentially unknowable (even dynamically) without running a cycle-detecting collector, which Swift long ago decided against as part of its standard runtime.

The argument that that makes the feature less useful is rooted in the statement that you cannot know that the function is called by a specific point in the program. And, of course, if that’s what you’re trying to prove, you should’ve made the function non-escaping within a scope that ends before that point. The point of the function being escaping is to not have such limitations.

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [November 6, 2026, 3:40am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/12 "2026-11-06T03:40:04Z")

</div>

I think this is equivalent to saying "Safe code must not use the at-least-`@once`-ness of a closure to enforce safety" (the at-most-once-ness is fine).

Given that standpoint, then, what's the point in having `@once` at all? I think _only_ the difference in the body of a function which accepts an `@once` closure, where control flow analysis can generate compilation errors if an execution path misses a call. Outside of lexical contexts, we're effectively throwing up our hands in despair anyway.

It makes me wonder if the correct design is not to introduce `@once` at all, and instead introduce an `@mustConsume` attribute that can be applied to any parameter or local variable of _any_ noncopyable type, that provides the flow-sensitive analysis that `@once` is providing.

[edit] I guess the "no storing it in `Deinitable`" is very helpful too. Though the easy escape hatch is still making me uncomfortable.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [November 6, 2026, 3:50am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/13 "2026-11-06T03:50:46Z")

</div>

> [@KeithBauerANZ](#):
>
> I think this is equivalent to saying "Safe code must not use the at-least-`@once`-ness of a closure to enforce safety" (the at-most-once-ness is fine).

I am not aware of any kind of safety that depends on code running at an unspecified point in the future as long as it’s before process exit, and there had better not be one, because we absolutely do not make that promise on any level. Total progress is a very, very hard thing for a general purpose programming language to prove.

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [November 6, 2026, 3:54am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/14 "2026-11-06T03:54:04Z")

</div>

I originally implemented these attributes as `@called(exactlyOnce)` and `@called(atMostOnce)` and after I spent enough time reading them repeatedly I came away feeling that they just looked _very clunky_. That led me to the conclusion that `@once` is the most obvious, elegant spelling for a type that only executes once, and it's available; we should use it!

The asymmetry is admittedly a bit unsatisfying but I want us to seriously consider using the best available spelling for the most common execution semantic. Would a more satisfying counterpart to `@once` be just `@atMostOnce`? I'd be fine with that too.

I also wonder if symmetry in these attributes would matter to us as much if we spread out the introduction of these attributes over many years. Is sharing a common design amongst the exactly-once, at-most-once, and sequentially attributes really important, or do they just need to be clear on their own?

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [November 6, 2026, 3:54am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/15 "2026-11-06T03:54:38Z")

</div>

> [@KeithBauerANZ](#):
>
> Given that standpoint, then, what's the point in having `@once` at all? I think _only_ the difference in the body of a function which accepts an `@once` closure, where control flow analysis can generate compilation errors if an execution path misses a call. Outside of lexical contexts, we're effectively throwing up our hands in despair anyway.

Non-escaping `@once` does make the guarantee you want _if the end of the scope is actually reached_, and escaping `@once` still offers a very practical level of verification that the programmer hasn’t forgotten about the value on some path.

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [November 6, 2026, 4:45am UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/16 "2026-11-06T04:45:58Z")

</div>

> [@j-f1](#):
>
> Can you include the declarations of the `Copyable`, `Escapable`, and `Deinitable` protocols in the pitch? It wasn’t clear to me which ones inherit from each other now.

They currently look like this:

```swift
@_marker public protocol Copyable: Deinitable/*, ~Escapable*/ {}
@_marker public protocol Escapable/*: ~Copyable*/ {}
@_marker public protocol Deinitable/*: ~Copyable, ~Escapable*/ {}

```

The choice to make `Copyable` refine `Deinitable` was an attempt to mitigate the type checking performance impact of introducing a third invertible protocol. The refinement is not designed to be load-bearing for anything and could be removed in the future with a corresponding update to the compiler if we decide to make `Deinitable` a user-facing protocol in the future and want to make them independent.

> [@j-f1](#):
>
> Did you consider importing nullable `called_once` blocks as `@callable(once)` types so that they’re allowed to be optional? (This could always be reversed when `Optional: ~Deinitable` in the future).

That's an option, but it would involve multiple iterations of churn since each time we update the import rules existing code that implements those imported interfaces will get new warnings about no longer matching. It's probably worth it, though.

> Similarly, can you include a discussion of the source compatibility impacts of moving from `@once` to `@callable(once)` in an API (or vice versa)?

I feel like this is already covered by the function conversion rules section. I can try to generalize the text of the source compatibility section to make it clear that the effects of narrowing or widening the parameters of an API can include moving from `@callable(once)` to `@once` and vice versa, though.

> Do you envision updating any protocols in the standard library to use called-once function types?

That's a good question. There don't seem to be many protocol requirements that would benefit. The closure passed to `Sequence.withContiguousStorageIfAvailable(_:)` ought to be `@callable(once)` and the closures passed to `StringProtocol.withCString(_:)` and `StringProtocol.withCString(encodedAs:_:)` ought to be `@once`. If anyone thinks there are more, let me know. Evolving protocol requirements would be tricky, so it's probably a good thing that we don't have many examples. I suspect we should leave these alone.

> In the “ Only offer `@once` without `@callable(once)`” section, you say “this would forfeit the ability to improve noncopyable and non-`Sendable` type ergonomics for many widely used APIs.” Could you elaborate on the kinds of APIs that would need these semantics?

Sure, a few good examples from the standard library APIs that could adopt `@callable(once)` are:

- the autoclosures operands of `&&` and `||`,
- `Optional.map(_:)`, `Optional.flatMap(_:)`, `Result.map(_:)`, etc.
- the default value autoclosure of `Dictionary.subscript(key:default:)`,
- `Mutex.withLockIfAvailable(_:)`,
- The cancellation handler of `withTaskCancellationHandler(operation:onCancel:)`

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [November 6, 2026, 2:00pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/17 "2026-11-06T14:00:45Z")

</div>

> [@John\_McCall](#):
>
> I am not aware of any kind of safety that depends on code running at an unspecified point in the future as long as it’s before process exit, and there had better not be one, because we absolutely do not make that promise on any level.

Yeah, and it’s worth mentioning specifically that resource leaks, while potentially very inconvenient for the developer, do not violate what we think of as memory safety.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [November 6, 2026, 2:21pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/18 "2026-11-06T14:21:46Z")

</div>

The latest iteration of this pitch looks great.

> Since calling a `@once` or `@callable(once)` function always consumes it, parameters with these function types are implicitly `consuming`

and later

> This restriction could be lifted in the future if borrowing these function values becomes useful, such as to pass them to generic functions that inspect them without consuming them.

Is it the right choice to default the implicit to `consuming` if we believe there might be value further down the road to lift the `borrowing` restriction? It would add yet another case of where something behaves differently than the "norm". I think I would personally rather write the `consuming` modifier out.

> withoutActuallyDeiniting

It is not directly spelled out so just making sure, there will also be an `async` variant of this method which is `nonisolated(nonsending)` and where the closure is also `async` + `nonisolated(nonsending)` right?

---

<div class="post-metadata">

**Author:** ![j-f1](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/j-f1/32/12287_2.png) [@j-f1](https://forums.swift.org/u/j-f1)\
**Post date:** [November 6, 2026, 2:28pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/19 "2026-11-06T14:28:14Z")

</div>

> [@tshortli](#):
>
> The choice to make `Copyable` refine `Deinitable` was an attempt to mitigate the type checking performance impact of introducing a third invertible protocol. The refinement is not designed to be load-bearing for anything and could be removed in the future with a corresponding update to the compiler

Thanks for sharing the hierarchy here! It makes a lot of sense to me that `Copyable` refines `Deinitable` — if you’re able to create a new copy of a value out of thin air, it should follow that you are also able to get rid of that copy once you are done with it. Otherwise it would never be clear whether calling a `consuming func` on such a value is intended to end its lifetime or not.

> [@tshortli](#):
>
> I feel like this is already covered by the function conversion rules section.

It probably is, but I think being explicit here would be helpful for folks who are considering updating their APIs or making new APIs in the future, to help them understand what would happen if they chose the wrong annotation.

> [@tshortli](#):
>
> Evolving protocol requirements would be tricky, so it's probably a good thing that we don't have many examples. I suspect we should leave these alone.

Yeah, that makes sense to me too. It’s a little unfortunate that these won’t get the safety improvements, but all three of these feel like things that could be better implemented with spans these days anyway.

And thanks for the stdlib examples! I have personally been bitten by `&&`/`||` before so I’m looking forward to seeing the change there. Another area that comes to mind after reading your list are the parameters to `assert` and friends, where there’s a similar issue with non-copyables as `&&.

---

<div class="post-metadata">

**Author:** ![Nickolas\_Pohilets](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nickolas_pohilets/32/10659_2.png) [@Nickolas\_Pohilets](https://forums.swift.org/u/Nickolas_Pohilets)\
**Post date:** [November 6, 2026, 3:04pm UTC](https://forums.swift.org/t/pitch-2-called-once-function-types/90515/20 "2026-11-06T15:04:45Z")

</div>

Can we have this diagnostic specifically on the branch that exits without calling `f`? Maybe one error per function with a note per branch.

```swift
func dropsConditionally(_ f: @once () -> Void, _ condition: Bool) { // error: 'f' is not called on all 
  if condition {
    return // note: 'f' is not called on this path
  } 
  f()
}

```

* * *

```swift
func borrowOnce(_ c: borrowing @once () -> Void) { } // error: '@once' cannot be used together with 'borrowing'

```

IMO, that's redundant. Attempt to call the function will diagnose the error anyway. This error won't be applied to other `~Copyable` or `~Deinitable` types, right? I'd prefer to avoid introducing extra special cases for closure types:

```swift
func borrowOnce(_ c: borrowing @once () -> Void) { } // error

struct Box<T: ~Deinitable> { var value: T }
func borrowOnce(_ c: borrowing Box<@once () -> Void>) { } // no error???

```

* * *

> Overrides of class members may not vary in their use of `@once` and `@callable(once)`. An overriding method, property, or subscript must declare `@once` and `@callable(once)` in exactly the same positions as the declaration it overrides, even where the [function conversion rules](#function-conversions) would allow the difference:

Why? Wouldn't allowing this help with source-compatibility?

* * *

> Overloads may not differ only in whether a parameter is `@once` or `@callable(once)`, or only in the `@once` and `@callable(once)` attributes of their results:

```swift
func produce() -> () -> Void { ... }
func produce() -> @once () -> Void { ... } // error: invalid redeclaration

```

I guess the first overload of `produce` Is missing `@callable(once)` in the result type.

* * *

> Since `Optional` requires its wrapped type to be `Deinitable` (see [Storage](#storage)), optional `@once` function types cannot be formed, so `called_once` parameters that are `_Nullable` or `_Null_unspecified` are imported as ordinary optional function types:

Why not optional `@callable(once)`?

[Next page](https://forums.swift.org/t/pitch-2-called-once-function-types/90515.md?page=2)
