33* Proposal: [ SE-0532] ( 0532-optional-noncopyable-improvements.md )
44* Author: [ Alejandro Alonso] ( https://github.com/Azoy )
55* Review Manager: [ John McCall] ( https://github.com/rjmccall )
6- * Status: ** Active review (May 26th...June 8th , 2026)**
6+ * Status: ** Active review (May 26th...July 6th , 2026)**
77* Implementation: [ swiftlang/swift #88505 ] ( https://github.com/swiftlang/swift/pull/88505 )
8+ * Previous revision: [ 1] ( https://github.com/swiftlang/swift-evolution/blob/49216cb8b9063e6031eca47033067f3224386b57/proposals/0532-optional-noncopyable-improvements.md )
89* Review: ([ pitch] ( https://forums.swift.org/t/pitch-optional-noncopyable-improvements-and-generalizations/86656 ) ) ([ review] ( https://forums.swift.org/t/se-0532-optional-noncopyable-improvements-and-generalizations/86941 ) )
910
1011## Summary of changes
1112
12- Introduces three new methods on ` Optional ` to help support noncopyable wrapped
13- values: ` borrow() ` , ` mutate() ` , and ` insert ()` . Also generalizes ` map ` ,
14- ` flatMap ` , and ` unsafelyUnwrapped ` .
13+ Introduces two new properties and a new method on ` Optional ` to help support
14+ noncopyable wrapped values: ` ref ` , ` mutableRef ` , and ` put ()` . Also generalizes
15+ ` map ` , ` flatMap ` , and ` unsafelyUnwrapped ` .
1516
1617## Motivation
1718
@@ -92,7 +93,7 @@ noncopyable wrapped values being more verbose than its predecessor.
9293
9394## Proposed solution
9495
95- We introduce two new methods on ` Optional ` : ` borrow() ` and ` mutate() ` . These will
96+ We introduce two new properties on ` Optional ` : ` ref ` and ` mutableRef ` . These will
9697return references to the inner wrapped payload if there is one and ` nil `
9798otherwise.
9899
@@ -101,7 +102,7 @@ func bar(_ x: borrowing SomeNoncopyable) {
101102 ...
102103}
103104
104- if let payload = optional .borrow () {
105+ if let payload = optional .ref {
105106 bar (payload.value ) // 'bar' gets passed a 'borrowing Wrapped'
106107}
107108
@@ -113,7 +114,7 @@ func baz(_ x: inout SomeNoncopyable) {
113114 ...
114115}
115116
116- if var payload = optional .mutate () {
117+ if var payload = optional .mutableRef {
117118 baz (& payload.value ) // 'baz' can mutate the payload in place!
118119}
119120
@@ -148,7 +149,7 @@ optMutex?.withLock { ... } // error: use of 'optMutex' after consume
148149
149150------
150151
151- A quality of life API we're also proposing is ` Optional.insert ` . Consider the
152+ A quality of life API we're also proposing is ` Optional.put() ` . Consider the
152153following pattern:
153154
154155``` swift
@@ -174,7 +175,7 @@ cache.opt!.append(newItem)
174175The use of ` ! ` here is really unnecessary because we already know there's a value
175176in the optional. In some cases, this ` ! ` may not get optimized away if
176177you're calling into a non-inlined function taking ` Cache ` because it can't make
177- any assumptions about the values that exist in it. We can safely model an ` insert `
178+ any assumptions about the values that exist in it. We can safely model a ` put() `
178179method that returns a direct mutable reference to the payload of an optional
179180given a new item to put into the optional:
180181
@@ -188,7 +189,7 @@ var cache = Cache()
188189// do some computation
189190
190191let items: UniqueArray<Int > = fooBar ()
191- var itemsRef = cache.opt .insert (items)
192+ var itemsRef = cache.opt .put (items)
192193
193194// more calculations, maybe some
194195// API calls
@@ -199,36 +200,40 @@ itemsRef.value.append(newItem)
199200
200201## Detailed design
201202
202- ### ` borrow() ` and ` mutate() `
203+ ### ` ref ` and ` mutableRef `
203204
204205``` swift
205206extension Optional where Wrapped: ~Copyable & ~Escapable {
206207 /// Returns a borrowed reference to the payload within the optional, if there
207208 /// is one.
208- @lifetime (borrow self )
209- public func borrow () -> Ref<Wrapped>?
209+ public var ref: Ref<Wrapped>? {
210+ @lifetime (borrow self )
211+ get
212+ }
210213}
211214
212215extension Optional where Wrapped: ~Copyable {
213216 /// Returns the mutable reference to the payload within the optional, if there
214217 /// is one.
215- @lifetime (& self )
216- public mutating func mutate () -> MutableRef<Wrapped>?
218+ public var mutableRef: MutableRef<Wrapped>? {
219+ @lifetime (& self )
220+ mutating get
221+ }
217222}
218223```
219224
220- Conceptually, these methods effectively move the ownership of the optional and
221- its payload. In order to call ` borrow() ` , for example, you must have at least
225+ Conceptually, these properties effectively move the ownership of the optional and
226+ its payload. In order to call ` ref ` , for example, you must have at least
222227a ` borrowing Optional<T> ` which, if you squint hard enough, is ` Ref<Optional<T>> ` .
223- ` borrow() ` takes this ` Ref<Optional<T>> ` and produces ` Optional<Ref<T>> ` which
228+ ` ref ` takes this ` Ref<Optional<T>> ` and produces ` Optional<Ref<T>> ` which
224229moved the reference inside the optional meaning we get back an owned value we
225230can mutate, consume, or simply have exclusive access to.
226231
227- The same is true for ` mutate() ` . It takes at least ` inout Optional<T> ` to be able to
232+ The same is true for ` mutableRef ` . It takes at least ` inout Optional<T> ` to be able to
228233perform the call which can look like ` MutableRef<Optional<T>> ` into an owned
229234` Optional<MutableRef<T>> ` value.
230235
231- ### ` insert ()`
236+ ### ` put ()`
232237
233238``` swift
234239extension Optional where Wrapped: ~Copyable {
@@ -241,7 +246,7 @@ extension Optional where Wrapped: ~Copyable {
241246 /// - Returns: A mutable reference inside the optional to its newly inserted
242247 /// payload.
243248 @lifetime (& self )
244- public mutating func insert (_ new : consuming Wrapped) -> MutableRef<Wrapped>
249+ public mutating func put (_ new : consuming Wrapped) -> MutableRef<Wrapped>
245250}
246251```
247252
@@ -290,13 +295,13 @@ func foo(x: consuming Optional<UniqueArray<String>>) -> Optional<String> {
290295}
291296
292297func bar (x : borrowing Optional <Atomic<Int >>) -> Optional <Int > {
293- x.borrow () .map { // ok!
298+ x.ref .map { // ok!
294299 $0 .value .load (ordering : .relaxed ) &+ 1
295300 }
296301}
297302
298303func baz (x : inout Optional <UniqueArray<Int >>) -> Optional <Int > {
299- x.mutate () .map {
304+ x.mutableRef .map {
300305 // Update the array while mapping over it
301306 $0 .value .append (123 )
302307 return $0 .value .count
@@ -306,7 +311,7 @@ func baz(x: inout Optional<UniqueArray<Int>>) -> Optional<Int> {
306311
307312## Source compatibility
308313
309- ` Optional.borrow() ` , ` Optional.mutate() ` , and ` Optional.insert () ` are new
314+ ` Optional.ref ` , ` Optional.mutableRef ` , and ` Optional.put () ` are new
310315methods so they shouldn't introduce any source compatibility issues.
311316
312317The proposed overloads of ` map ` and ` flatMap ` are less-specialized overloads of
@@ -328,7 +333,7 @@ don't come with any new ABI nor break any old ABI.
328333
329334## Implications on adoption
330335
331- The ` Optional.borrow() ` , ` Optional.mutate() ` , and ` Optional.insert () `
336+ The ` Optional.ref ` , ` Optional.mutableRef ` , and ` Optional.put () `
332337methods will have the same availability as ` Ref ` and ` MutableRef ` . The rest of
333338the generalizatons will be marked as always available.
334339
@@ -348,7 +353,7 @@ if borrow x = optional {
348353foo (optional ) // ok
349354```
350355
351- If we decided this was a better direction than the ` borrow() ` and ` mutate() `
356+ If we decided this was a better direction than the ` ref ` and ` mutableRef `
352357story, then we'd need to rethink how we want to generalize ` map ` , ` flatMap ` , and
353358` unsafelyUnwrapped ` because they can no longer be always consuming. We can provide
354359` consumingMap ` , ` borrowingMap ` , ` mutatingMap ` , etc. which is one solution, but
@@ -369,7 +374,7 @@ stable OS copies the wrapped payload.
369374
370375### Automatic dereferencing for ` Ref ` and ` MutableRef `
371376
372- In the proposed solution, the examples using ` borrow() ` and ` mutate() ` to do a
377+ In the proposed solution, the examples using ` ref ` and ` mutableRef ` to do a
373378` map ` needed to explicitly access the ` .value ` property on these reference
374379types. This isn't quite as ergonomic as the existing ` map ` on ` Optional ` that
375380let's you interact with the passed parameter as the type itself. We could give
@@ -378,7 +383,7 @@ dereference themselves when accessing member properties or methods on them:
378383
379384``` swift
380385func bar (x : borrowing Optional <Atomic<Int >>) -> Optional <Int > {
381- x.borrow () .map { // ok!
386+ x.ref .map { // ok!
382387 // No more '.value.'
383388 $0 .load (ordering : .relaxed ) &+ 1
384389 }
@@ -395,18 +400,14 @@ which would be useful for `UniqueBox` as well.
395400### Change the default ownership of Optional bindings
396401
397402In the motivation for some of the methods of this proposal, it's stated that we
398- need methods like ` borrow() ` and ` mutate() ` to allow for borrowing versions of
403+ need properties like ` ref ` and ` mutableRef ` to allow for borrowing versions of
399404control flow. We could instead change the default ownership of these ` if let `
400405scenarios to be borrowing by default. However, this would be a source-breaking
401406change for code that expects optional binding to be consuming.
402407
403- ### ` Optional.ref ` and ` Optional.mutableRef ` properties
404-
405- Instead of the ` borrow() ` and ` mutate() ` method names, we could have properties
406- that returned the same value like the various ` .span ` and ` .mutableSpan `
407- properties.
408+ ### ` Optional.borrow() ` and ` Optional.mutate() ` methods
408409
409- However, we feel that the nature of the verbs ` borrow ` and ` mutate ` fit quite
410- well in API usage especially for things like ` opt.borrow().map { ... } ` . It also
411- mimics the recently accepted [ Borrow Accessors SE-0507 ] ( https://github.com/swiftlang/swift-evolution/blob/main/proposals/0507-borrow-accessors.md )
412- names .
410+ In a previous revision of this proposal, we suggesed the method names ` borrow() `
411+ and ` mutate() ` instead of the ` ref ` and ` mutableRef ` properties. It was decided
412+ that the properties were more desired as they somewhat mimic the ` span ` and
413+ ` mutableSpan ` properties found on types like ` InlineArray ` and ` UniqueArray ` .
0 commit comments