-
[SE-0507] Borrow and Mutate AccessorsSwift 2026. 2. 8. 08:14
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 SE-0507 Borrow and Mutate Accessors에 대해 정리해보겠습니다 🙋🏻

Intro
Swift의 property accessor는 계속 발전중입니다.
기존에는 get, set, 그리고 최근 추가된 yielding borrow, yielding mutate가 있었는데요.
이번 SE-0507은 새로운 borrow와 mutate accessor를 제안합니다.
얘네들은 borrowing semantics를 사용해서 복사 오버헤드 없이 값에 접근할 수 있고, yielding accessor보다 성능이 좋습니다.
특히 non-copyable 타입을 다루는 collection이나 성능이 중요한 저수준 데이터 구조에 유용할 거예요 🚀
현재 2026년 2월 9일까지 리뷰가 진행 중이긴한데 현 시점에서 Draft 상태라 계획대로 내일까지 반영될진 지켜봐야 알것 같아요.
왜 필요한가?
기존 accessor들은 각각 한계가 있습니다.
문제 1: get은 복사해야 한다
get accessor는 값을 복사하거나 새로 생성해서 반환해야 합니다.
복사의 코스트가 많이 들거나 불가능한 경우엔 쓸 수 없죠.
struct NC: ~Copyable { ... } struct ContainerOfNoncopyable { private var _element: NC var element: Element { return _element // 🛑 ERROR: Cannot copy `_element` } }Non-copyable 값을 저장하는 collection은 subscript에 get을 쓸 수 없습니다.
문제 2: yielding accessor는 오버헤드가 크다
yielding mutate와 yielding borrow는 coroutine을 사용합니다.
접근 전후로 코드를 실행할 수 있어서 유연하지만, 그만큼 오버헤드가 있습니다.
- Coroutine을 위한 메모리 할당
- 여러 번의 함수 호출
- 접근 scope가 제한됨 (함수가 끝나기 전에 완료되어야 함)
struct Element: ~Copyable { var span: Span<...> { ... } } struct Wrapper: ~Copyable { private var _element: Element var element: Element { yielding borrow { // ❗️Note: Using `yielding borrow` accessor yield _element } } } func getSpan(wrapper: borrowing Wrapper) -> Span<...> { // Because we're reading `element` from a yielding accessor, // its access must finish before `getSpan` returns. // But `span` cannot outlive `element`, so ... // 🛑 ERROR: lifetime-dependent value escapes its scope return wrapper.element.span }Borrowing accessor는 이 두 문제를 모두 해결합니다.
제안된 솔루션
새로운 borrow와 mutate 키워드로 accessor를 정의합니다.
struct RigidWrapper<Element: ~Copyable>: ~Copyable { var _element: Element var element: Element { borrow { return _element } mutate { return &_element } } }- borrow: 읽기 전용 접근, 복사하지 않음
- mutate: 읽기/쓰기 접근, &로 mutable reference 반환
yield 대신 return을 쓰는 게 차이점입니다.
물론 single expression이면 return 키워드는 생략 가능합니다.
상세 설계
반환 값의 제약
Borrowing accessor는 저장된 값만 반환할 수 있습니다.
local이나 temporary 값은 반환할 수 없어요.
struct InvalidExamples { var _array : [Int] var local: [Int] { borrow { let foo = [1, 2, 3] // 🛑 ERROR: Cannot return local value from borrow accessor return foo } } var temporary: [Int]? { borrow { // This would require creating a temporary local // optional array from `_array`. // 🛑 ERROR: Cannot return temporary value from borrow accessor return _array } } }반환하는 값은 accessor 실행이 끝난 후에도 유효해야 합니다.
사용 방법
borrow로 읽기
클라이언트 코드는 기존 get과 동일하게 보이지만, 내부적으로는 복사가 일어나지 않습니다.
var owner = Wrapper(value) // "borrow" the value to give to a function // without copying... doSomething(with: owner.element) func doSomething(with value: borrowing Element) { // `value` is borrowed, so this invokes // the method "in-place" value.someMethod() // Exclusivity prevents the owner from being // mutated while `value` is alive: owner.mutatingMethod() // 🛑 ERROR }메모리 일관성을 위해 Swift의 exclusivity rule이 적용됩니다.
borrow가 활성화된 동안엔 owner를 변경할 수 없어요.
mutate로 수정하기
mutate accessor는 읽기/쓰기 접근을 제공합니다.
var owner = Wrapper(value) // Mutating/inout access will invoke the `mutate` accessor doSomething(with: &owner.element) func doSomeMutation(with value: inout Element) { // So this invokes a method on the value "in-place" // Because you borrowed for mutation, this can be // a mutating method. value.someMutatingMethod() // Accessing the owner is an exclusivity violation owner.anyMethod() // 🛑 ERROR }
다른 accessor와의 호환성
mutate를 제공하면
- borrow도 반드시 제공해야 함
- yielding mutate나 yielding borrow는 사용 불가
Swift는 일반적으로 write-only property를 허용하지 않습니다.
또한 읽기와 쓰기 작업의 접근 scope를 일관되게 유지해야 합니다.
borrow를 제공하면
- get이나 yielding borrow는 사용 불가
여러 read accessor나 여러 write accessor를 동시에 정의하면 호출자 입장에서 혼란스럽기 때문입니다.
Ownership 변형
기본적으로 아래와 같아요.
- borrow: 포함하는 값을 변경하지 않음
- mutate: 포함하는 값을 변경함
이걸 mutating이나 nonmutating 키워드로 오버라이드할 수 있습니다.
mutating borrow
읽기 전용이지만 side-effect로 인해 포함하는 값이 변경될 수 있는 경우입니다.
struct S1 { private var cachedValue: Foo var foo : Foo { mutating borrow { if !cachedValue.available { // Update `cachedValue` // Compiler allows such update // because this is `mutating` } return cachedValue } } } let s1: S1 // Note: Immutable value s1.foo // 🛑 Cannot use mutating accessor on immutable value캐시를 업데이트하는 경우 같은 거죠.
nonmutating mutate
값을 변경할 수 있지만 부모 값의 변경으로 간주되지 않는 경우입니다.
struct Outer { var inner: InnerType { borrow { return some_value_stored_elsewhere } nonmutating mutate { return &some_value_stored_elsewhere } } }외부에 저장된 값에 접근하는 경우 같은 거예요.
Protocol requirement로 사용
Protocol에서도 borrowing accessor를 요구할 수 있습니다.
protocol BorrowingAccess { associatedtype Element var element: Element { borrow mutate } }이는 두 가지 기능이 있어요.
- Protocol을 통한 접근 방식을 제어 (existential이나 generic argument에서)
- conforming 타입에 해당 accessor가 있어야 함 (명시적 구현 또는 컴파일러 합성)
컴파일러 합성
- Stored property → borrow, mutate 합성 가능
- borrow 구현 → yielding borrow나 get 합성 가능 (copyable만)
- mutate 구현 → set이나 yielding mutate 합성 가능
제약사항
- Protocol이 borrow 요구 → conforming 타입도 borrow 필요
- Protocol이 mutate 요구 → conforming 타입은 borrow와 mutate 모두 필요
Class와 Actor에서는 불가
Class는 property 접근 전후로 runtime exclusivity check를 실행해야 합니다.
Borrowing accessor는 접근 후에 코드를 실행할 방법이 없어서 class property에는 사용할 수 없습니다.
yielding borrow와 yielding mutate는 class property에 사용 가능합니다.
Subscript에도 사용 가능
struct ArrayLikeType { subscript(index: Int) -> Element { borrow { .... } mutate { .... } } }다만 subscript는 전체 struct를 암묵적으로 접근하므로, 아래 코드는 불가능해요.
var x: ArrayLikeType swap(&x[0], &x[1]) // 🛑 두 개의 mutating access
호환성
Source compatibility
기존에 borrow나 mutate라는 이름의 함수를 trailing closure로 호출하는 경우와 충돌 가능성이 있습니다.
struct S { func borrow(closure: () -> ()) { ... } // Is this a new borrow accessor? // Or a call to the borrow method just above? var property: Int { borrow { ... } } }하지만 실제로는 거의 발생하지 않을 것으로 봅니다.
ABI compatibility
새로운 기능이라 기존 ABI에는 영향이 없습니다.
Adoption 영향
Non-borrowing accessor를 borrowing accessor로 바꾸는 건 일반적으로 ABI-breaking입니다.
하지만 existential type의 ABI는 보존됩니다. (컴파일러가 계속 accessor를 합성할 수 있다면)
Source-breaking일 수도 있습니다. 특히 get을 borrow로 바꾸면 lifetime 제약이 생겨서 기존 코드가 컴파일되지 않을 수 있어요.
향후 방향성
Borrowing returns
함수에서도 borrowed 값을 반환할 수 있으면 유용합니다.
struct S<Value> { subscript(_ index: Int) -> Value { borrow { ... } } func indirect(_ parameter: Foo) -> borrowing Value { let index = ... compute index from parameter ... return self[index] } }
Unsafe pointer를 통한 borrowing
저수준 데이터 구조는 종종 unsafe pointer를 사용합니다.
var _storage: UnsafePointer<Element> var first: Element { borrow { // ERROR: borrow accessors can only return stored properties // or computed properties that have borrow accessors return _storage.pointee } }이런 케이스를 지원하려면 뭔가 annotation이 필요할 것 같습니다.
var first: Element { borrow { return unsafeResultDependsOnSelf(_storage.pointee) } }
나왔던 대안
아무것도 하지 않기?
Yielding coroutine-based accessor도 비슷한 기능을 제공하지만, 성능 특성이 다릅니다.
Coroutine accessor는 접근 후에 코드를 실행할 수 있어서 의미론적으로는 더 강력하지만, 완전히 inline되지 않으면 여러 함수 호출 오버헤드가 있습니다.
Borrowing accessor는 여러 함수 호출 오버헤드 없이 in-place mutation 기능을 제공합니다.
Conclusion
특히나 유용한 제안이라고 생각되는 포인트는 non-copyable 타입을 다루는 collection이나 성능이 중요한 저수준 코드에서 큰 도움이 될 것 같아요.
get의 복사 오버헤드와 yielding accessor의 coroutine 오버헤드 사이의 sweet spot을 찾은 느낌입니다.
Swift Standard Library 팀에서도 이 기능을 원했다고 하니, 실무에서 정말 필요한 기능인 것 같네요 😃
References
swift-evolution/proposals/0507-borrow-accessors.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
github.com
[Pitch] Borrowing Accessors
I just put up the draft proposal for Borrowing Accessors, which together with Yielding Accessors completes the full suite of accessor support described in the Prospective Vision for Accessors. More complete details are in the draft proposal. The following
forums.swift.org
SE-0507: Borrow and Mutate Accessors
Hi everyone, The review of SE-0507 "Borrow and Mutate Accessors" begins now and runs through February 9, 2026. Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to
forums.swift.org
[Prospective Vision] Accessors
Hello, Swift Community. The Language Steering Group would like to gather feedback on a prospective vision for accessors in Swift. Vision documents help describe an overall direction for Swift. The actual Swift changes for executing on the vision will come
forums.swift.org
'Swift' 카테고리의 다른 글
[SE-0506] Advanced Observation Tracking (0) 2026.02.01 [SE-0493] defer support async (0) 2026.01.24 [SE-0504] Task Cancellation Shields (1) 2026.01.17 [SE-0502] Exclude private initialized properties from memberwise initializer (0) 2026.01.11 Embedded Swift Improvements Coming in Swift 6.3 (0) 2025.12.26