# \[Pitch\] \`@noImplicitCopy\` attribute for local variables and function parameters

**URL:** <https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506>\
**Category:** Pitches\
**Created:** [November 17, 2022, 7:25pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506 "2022-11-17T19:25:01Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [November 17, 2022, 7:25pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/1 "2022-11-17T19:25:01Z")

</div>

Hi everyone! Another feature we're working on to provide tools for predictable performance is a way to fully suppress implicit copying on specific variables, and let you manually `copy` them where necessary. We hope this will provide a wider-scoped, but still localized, tool for controlling the compiler's copy behavior than things like the [`take` operator]. It's also a good building block on the way to move-only types that we think will still be valuable even when we have those, since we expect that a lot of code will still be generally fine with implicitly-copyable types and only want to take explicit control in sensitive parts of the codebase. I've put up a draft proposal for you all to start reading here:

> <https://github.com/apple/swift-evolution/pull/1846>

A few things in particular I'm looking for feedback on:

- The name `@noImplicitCopy` says what it does, I guess, but is undeniably clunky.
- Once we take away the ability to implicitly copy or retain a value, we need to account for what operations on the value are borrowing and consuming on the value. I started a list for both in the proposal, but I undoubtedly forgot some cases.

Thank you for your feedback!

---

<div class="post-metadata">

**Author:** ![mtsrodrigues](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mtsrodrigues/32/34169_2.png) [@mtsrodrigues](https://forums.swift.org/u/mtsrodrigues)\
**Post date:** [November 17, 2022, 7:49pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/2 "2022-11-17T19:49:14Z")

</div>

> [@Joe\_Groff](#):
>
> The name `@noImplicitCopy` says what it does, I guess, but is undeniably clunky.

Suggestion: `@copying(explicit)`. And maybe there could be a `@copying(forbidden)` if it makes sense to forbidden copy at all, even using the `copy` operator.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [November 17, 2022, 9:04pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/3 "2022-11-17T21:04:29Z")

</div>

> [@mtsrodrigues](#):
>
> And maybe there could be a `@copying(forbidden)` if it makes sense to forbidden copy at all, even using the `copy` operator.

Our thinking for this attribute is that it should remain non-transitive, meaning that you can pass your copy-restricted bindings to other functions that may still copy them, since to do otherwise would require an expensive audit of existing code to annotate what functions internally do not copy their arguments, and that at that level of effort, adopting move-only types might be a better investment. Do you think `@copying(forbidden)` would still be useful as a local constraint?

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [November 17, 2022, 9:19pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/4 "2022-11-17T21:19:29Z")

</div>

> [@Joe\_Groff](#):
>
> Our thinking for this attribute is that it should remain non-transitive, meaning that you can pass your copy-restricted bindings to other functions that may still copy them, since to do otherwise would require an expensive audit of existing code to annotate what functions internally do not copy their arguments, and that at that level of effort, adopting move-only types might be a better investment.

I see the ergonomic reason for this, but it's somewhat unfortunate that `@noImplicitCopy` really only means "no implicit copy visible directly within this scope"—it seems like the attribute... overpromises what it actually protects from. It would still be local-only, for instance, to require _potentially_ copying uses of a `@noImplicitCopy` binding to be annotated with `copy`, but perhaps this would require `copy` in too many places in practice...

Somewhat relatedly, would it potentially be desirable for an explicit `borrow` parameter to _imply_ `@noImplicitCopy`? It seems like you'd do this when you specifically want to avoid copying, so it might be appropriate to ensure you don't actually end up copying the value internally. But this would introduce a difference between implicitly `borrow` parameters and explicitly `borrow` parameters which might be undesirable.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [November 17, 2022, 9:33pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/5 "2022-11-17T21:33:41Z")

</div>

> [@Joe\_Groff](#):
>
> The name `@noImplicitCopy` says what it does, I guess, but is undeniably clunky.

Before having read the document, my naive impression regarding a `@noImplicitCopy` binding was simply that one would have to either explicitly `copy` or explicitly ~~`move`~~ `take`.

Having read it now, I see that what's perhaps even more salient to the feature than "no implicit copy" is the "eager move" ("eager take"?) aspect. Without attempting to nail down a perfect non-clunky name, I'd suggest that this should be foregrounded in how the feature is described and taught.

---

<div class="post-metadata">

**Author:** ![ensan-hcl](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ensan-hcl/32/15186_2.png) [@ensan-hcl](https://forums.swift.org/u/ensan-hcl)\
**Post date:** [November 18, 2022, 1:00am UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/6 "2022-11-18T01:00:05Z")

</div>

I'm not sure if I understand correctly, but I have a small concern on this feature.

```swift
@noImplicitCopy let x = 42
func foo(_ value: take Int) {}
func bar(_ value: Int) {}

// not Error
foo(copy x)
bar(x)

```

However, after the author of `foo` changes the function into `borrow`, it still compiles without error.

```swift
// modified function
func foo(_ value: borrow Int) {}

// still not Error
foo(copy x)
bar(x)

```

Here, no implicit copy happens by default, but the `copy` operator remains even though it's no longer necessary and actually wasteful. I believe this type of change happens to some extent. In order to avoid this kind of mistake, should there be some warning for non-sense `copy` usages?

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [November 18, 2022, 1:14am UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/7 "2022-11-18T01:14:46Z")

</div>

> [@ensan-hcl](#):
>
> `copy` operator remains even though it's no longer necessary and actually wasteful.

IIUC, `copy` doesn’t _guarantee_ that there’s some sort of memory-level copy that _actually_ occurs—the optimizer is still free to eliminate unnecessary copies. So at least in trivial cases it seems like this _shouldn’t_ be wasteful.

---

<div class="post-metadata">

**Author:** ![Nobody1707](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nobody1707/32/2169_2.png) [@Nobody1707](https://forums.swift.org/u/Nobody1707)\
**Post date:** [November 18, 2022, 4:31pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/8 "2022-11-18T16:31:10Z")

</div>

You're right, but I think warning here would still be helpful.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [December 1, 2022, 11:29pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/9 "2022-12-01T23:29:09Z")

</div>

@Michael_Gottesman has gotten his prototype implementation to support `@noImplicitCopy` on mutable variables as well, so [I've updated the proposal](https://github.com/apple/swift-evolution/pull/1846) to reflect this.

---

<div class="post-metadata">

**Author:** ![benrimmington](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/benrimmington/32/695_2.png) [@benrimmington](https://forums.swift.org/u/benrimmington)\
**Post date:** [December 2, 2022, 9:47am UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/10 "2022-12-02T09:47:17Z")

</div>

> [@Joe\_Groff](#):
>
> A few things in particular I'm looking for feedback on:
> 
> - The name `@noImplicitCopy` says what it does, I guess, but is undeniably clunky.

Would the name `@consumable` make any sense? There isn't an implicit `copy`, but there does appear to be an implicit `consume` in the "eager-move" semantics.

---

<div class="post-metadata">

**Author:** ![Andrew\_Trick](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrew_trick/32/323_2.png) [@Andrew\_Trick](https://forums.swift.org/u/Andrew_Trick)\
**Post date:** [December 5, 2022, 9:10pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/11 "2022-12-05T21:10:53Z")

</div>

Some background for bike-shedding... `@eagerMove` would be a better name, but we also need to be able to talk about "eager-move" types. Our CoW types, Array, Set, and Dictionary, actually have eager-move semantics. In the future, there will be some way for programmers to annotate their own copy-on-write types, or value-like types in general, and those will be eager-moved. In the meantime, it can be forced with an `@_eagerMove` attribute.

Of course, these types are still implicitly copied. So we need to be careful not to confuse the type and variable attributes. Are we ok saying that the same attribute does more when applied to values (adds in a restriction on copying)?

We get into trouble with names like "move-only" and "consumable" because this attribute is also useful for borrowed values which cannot in fact be moved or consumed.

---

<div class="post-metadata">

**Author:** ![tbkka](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tbkka/32/7532_2.png) [@tbkka](https://forums.swift.org/u/tbkka)\
**Post date:** [January 4, 2023, 11:07pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/12 "2023-01-04T23:07:09Z")

</div>

The [borrow/inout](https://forums.swift.org/t/pitch-borrow-and-inout-declaration-keywords/62366) declarations that are being discussed also create bindings that are non-implicitly-copyable.

Following that pattern, we could add an entirely new binding keyword:

```swift
// `x` is a NON-implicitly copyable mutable value
// it is initialized from `c`
// `c` is out of scope after this
consuming x = c

// Compare: After SE-0366,
// `y` is an implicitly copyable mutable value
// It is initialized from `d`
// `d` is out of scope after this
var y = consume d

```

Andrew Trick [summarized this idea](https://forums.swift.org/t/pitch-borrow-and-inout-declaration-keywords/62366/46) in the borrow/inout bindings thread:

> [@Pitch: \`borrow\` and \`inout\` declaration keywords](https://forums.swift.org/t/pitch-borrow-and-inout-declaration-keywords/62366/46):
>
> Implicitly copying bindings: `let/var/inout`
> 
> Noncopying bindings: `borrow/consume/mutate`

---

<div class="post-metadata">

**Author:** ![Andrew\_Trick](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrew_trick/32/323_2.png) [@Andrew\_Trick](https://forums.swift.org/u/Andrew_Trick)\
**Post date:** [January 5, 2023, 6:56am UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/13 "2023-01-05T06:56:22Z")

</div>

> [@Pitch: \`borrow\` and \`inout\` declaration keywords](https://forums.swift.org/t/pitch-borrow-and-inout-declaration-keywords/62366/46):
>
> Noncopying bindings: `borrow/consume/mutate`

I should have said that the no-implicit-copy bindings could be spelled: `borrowing/consuming/mutating`.

This isn't a grammatical concern. Rather, we need to distinguish the binding keywords:

```swift
func f1(x: borrowing X) // keyword position is debatable
func f2(x: consuming X)
borrowing x =
consuming x =

```

From the operational keywords:

```swift
f1(borrow x)
f2(consume x)
f2(copy x)

```

The bottom line is that a growing subset of programmers want to migrate toward ownership control. Asking them to clutter their code with awkward attributes is not the way to encourage that. Binding keywords are the best way to control ownership and mesh well with the need to specify parameter ownership conventions.

---

<div class="post-metadata">

**Author:** ![johnburkey](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/johnburkey/32/20566_2.png) [@johnburkey](https://forums.swift.org/u/johnburkey)\
**Post date:** [January 23, 2023, 5:02pm UTC](https://forums.swift.org/t/pitch-noimplicitcopy-attribute-for-local-variables-and-function-parameters/61506/14 "2023-01-23T17:02:34Z")

</div>

I do appreciate this work, and I would add that there are two problems with ARC as it stands- it's over decorating of our code with ARC calls and copies, and the cost of ARC. (Even if we did the work below, its still silly/costly to incessantly retain/release when objects are static and immortal)

Related to the cost of ARC, there's a better paradigm where we don't use atomics when the compiler knows the allocations are local:

One could imagine if the function call to allocate the HeapObject under the swift object was aware of the locality of reference of the ptr being asked for then the ARC call could in most cases not be atomic, and not use a global malloc call. References could then be promoted to global space only when they enter it.

And when they are there, use the old ARC code.

This kind of move would directly address the other half of the problem- which is that swift currently doesn't do a good job of letting we developers communicate our intention of local work, local allocation to the operating system in a way that lets us take advantage of the performance inherent in modern hardware. (We can communicate it (via structs, or local refs, but because ARC is implemented as a global "WE NEED ATOMICS ALL THE TIME" , "WE NEED GLOBAL MALLOC" and because the implementations of Arrays etc use this stuff internally, our performance is mangled regardless.

If you are doing local alloc, and local compute, you don't need atomics, or a global allocator.

By putting it under the hood this way, developers would just benefit and not be exposed to the change directly. And it could be rolled out with @newarc pragma thing on specific instances for testing, and one of those "I want swift6 in my codebase" feature flags.

Also, I do think it's worth considering annotating whole class hierarchies as never copy. Oh, and in our work, we have found we are going to need a less reference counting happy Array. Its pretty hard to dodge Arrays all the time in performance needing code, and you don't want all of us dreaming up performant substitutes.
