When are you supposed to use ownership modifiers?

Using Optional as a reference, it seems to me like we ought to be decorating our code accordingly now. I haven't seen any good guide on when or how, though, ever. I also have no idea how to verify the correctness of any annotations. From what I've seen so far, it seems to me like a code analysis tool ought to be able to automatically add them, perhaps necessitating unit tests for verification of intended usage?

It's all quite confusing at this point.

If you're using them on copyable types (the default), they're just an optional performance optimization, so you'd verify them the same way as any other performance work: benchmarks and profiling tools (or examining disassembly/using @_assemblyVision to see that the copy you were attempting to eliminate is in fact gone).

If you're using them with non-copyable types, it won't compile if you have it wrong.

8 Likes

The "optional" is at the heart of what I'm asking…

The flexibility and intent is the first thing to be tested. It seems to me that not using annotations makes a strong statement about them. (I.e. "No, ~Copyables" are ~Allowed".) I don't see guidelines on when is this appropriate, and what general (potentially automated) practice should be on it—it seems like certain annotations ought to be default, rather than none.

I hope this does not come across as condescending or rude, but to me this is one of those topics where: "If you don't know you need it, you don't need it".

So, if you are asking "should I start annotating things because I see others doing it" the answer is pretty much "no". No worrying required.

If you are just interested under which circumstances these would apply, there is no single good answer (at least I don't have one) - this will be a bigger "learning project" about how things like ownership, memory, function calls, etc. "really" work.

If you have an actual performance topic to solve, you'll probably need to look at things more methodically anyway.

I can recommend learning a bit of rust - you can't really write rust without understanding a good chunk of it, so the swift ownership stuff (which is more hidden behind the scenes) will feel right at home afterwards.

5 Likes

All types default to be copyable, that’s automatic default for the Swift, since they are fine for majority use-cases. Non-copyable types is mostly can be seen as on-demand optimization technique where you don’t want to allow copies for some reason or that’s a generic wide-purpose library code.

If you don’t see how it can be applied in your code, great chances that you don’t need it (oh, @sliemeobn actually has already stated that, huh). Otherwise it would be clear what behavior you’d like to enforce on the type in your use case.

You see it in standard library definitions because they have to work in a large amount of cases without restricting usage. Like Optional type being generic over both copyable and non-copyable types, since it is just a wrapper around some user type.

2 Likes

I was hoping WWDC would offer something to help. It didn't.

I can't abide, "You already know all of the things you need to know. You don't need people who know more than you do to help you understand what they do".

Someone, please help fix this knowledge gatekeeping situation.

The reason "no annotations" is the default is because that's the correct choice for most code. Swift tries very hard to make the less complex option the usually-correct one.

Typically if you're using them for optimization purposes, you'd first identify a bottleneck in your code with profiling tools (e.g. Instruments), then determine that copying a value is contributing to that bottleneck (e.g. by looking for swift_retain, …initWithCopy, etc…), and then experiment with using the annotations to try to eliminate the copy. If I'm remembering correctly, method arguments are borrowed by default (most methods don't need to keep their arguments around after they finish running), and init arguments consume by default (most inits do want to store their arguments in the thing they're initing).

If you have semantic requirements that forbid copies, like being in certain low level or embedded environments, things are somewhat trickier for the moment, but I believe we're eventually hoping to productize the currently-experimental @_noAllocations annotation, which will point out the relevant spots with compile-time errors.

5 Likes

And some of those approaches are explored in Improve memory usage and performance with Swift - WWDC25 - Videos - Apple Developer with @nnnnnnnn. There are also some new features in Instruments this year: Optimize CPU performance with Instruments - WWDC25 - Videos - Apple Developer

5 Likes

That's the understatement of the year: instruction branch-level tracing in M4+ CPU's... !

I don't think anyone is gatekeeping here. Rather they are responding to this:

No, in most cases you oughtn't. If you are using ~Copyable types, then the annotations are necessary to explain the semantics of the operations to the compiler, but if you are not explicitly using ~Copyable, they are a relatively niche performance optimization to eliminate retain/release operations and sometimes dynamic exclusivity checks. @nnnnnnnn's WWDC talk (linked above: Improve memory usage and performance with Swift - WWDC25 - Videos - Apple Developer) goes into more detail on that, and introduces Span, which gives you a means to avoid those operations without needing these optimizations that will be more useful for most developers.

The standard library uses these annotations, because the standard library needs to be general purpose and support both copyable and non-copyable types (we are still in the process of updating it for complete support; it's a big project), and we need the standard library to be usable in environments where every extraneous retain/release matters. The vast majority of code is not in this situation, and therefore does not need these annotations--they would only add noise.

If you just want to learn more about what the annotations mean, there are lots of people who would be happy to explain why they are used on any given API, and the ways in which it's different from an unannotated API.

Finally: these annotations were actually introduced last year or earlier, so last year's WWDC talks have more information. @kavon gave one that covers their use with noncopyable types (Consume noncopyable types in Swift - WWDC24 - Videos - Apple Developer).

10 Likes

It would be great if the TSPL had a section for learn guides. And a primer on performant safety with Swift would be good as one of them. I'd ask if what was just written here could become a blog post, but with the lack of search at the moment it would likely get lost over time, but it still might be a nice first step with an eye towards that search feature down the line. (Jekyll -> Astro -> Ignite ;) )

All the video links are great and helpful and expertly crafted, but they aren't a guide exactly. They're like dropping in on a TV series where one may feel like one has missed some key episode. They also aren't written material that can be updated as the language changes. And while there are indeed lots of smart generous people who'd be will be willing to explain, there are also a lot of people who want to be explained to! Don't the people who know what's going on have a lot of work to do? Wouldn't it be nice if there was a URL that could be handed out where people could start?

"If you don't know, you don't need it" is a hard thing for a lot curious people to take as a response. Even though it can be meant to be reassuring ("It's okay! You aren't doing anything wrong by not using this!"), it can feel a lot like "Don't worry your pretty little head" on the receiving end.

Even if just started as page with all these videos and links to the pitches collected in one place that'd be a handy start. If one did pull that together in a .md file... to where should that pull request go? Is there a place yet?

4 Likes