The review of SE-0517: UniqueBox begins now and runs through March 13th, 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 keep your feedback private, directly to the review manager. When emailing the review manager directly, please keep the proposal link at the top of the message.
What goes into a review?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at
I think it can be Sendable even when value is non-sendable, as long as init and value.setter take their parameter as sending, consume() method returns sending value, and other methods (span, mutableSpan, clone() and value.getter) have where Value: Sendable. See DisconnectedBox that I've described here - How to: Pass a `sending` sequence parameter whose elements are `sending` - #14 by Nickolas_Pohilets.
But UniqueBox does not have to be the only tool for this job. Managing heap memory and wrapping disconnected regions are two different responsibilities. And forcing heap allocation when users need DisconnectedBox is also not good. So, ideally would be nice to have both. But this is probably out of scope of this proposal.
+1 on the proposal. I have needed such a type in a few places over the past year. I really like the change from the empty subscript to the property since this was initially pitched.
We have a similar type in a few places, including swift-async-algorithms. I agree that this is a useful type for modeling disconnected values in the type system, but I think this should be a distinct type than UniquePointer since Disconnected does not require a heap allocation to work.
In some sense it enables unique classes but without open functions.
Though it might a bit of side track, I wonder if classes might be addressed as well - could be covering both that way?
e.g.
class C1: Unique, Sendable {
open func foo() { ... }
}
final class C2: C1, Unique, Sendable {
override func foo() { ... }
}
While I understand that structures + protocols should cover all the cases, seems it is not always the case.
I think the final proposal has nicely integrated the (significant!) amount of feedback that was received during the pitch, and is all the better for it.
I still don't personally see the need for this type; it seems far less useful than Rust's Box due to far less support for noncopyable types in the ecosystem. A class-based box would be far more generally useful to me.
Very weak -1 — I don't see the need myself, haven't heard anyone articulate the need, and there's costs for having any kind of stdlib API. But if we agree there's need, this seems like a good design.
It was discussed in the pitch thread, but I am reiterating it here because the final proposal does not address it.
I am generally in favor of adding unique ownership utilities, but I am unsure if the proposed design is sufficiently general for the Standard Library in its current form.
My main question is: Do we intend for UniqueBox to serve as a universal currency type?
If the answer is yes, the current design seems restrictive. It's strictly tied to Swift's native alloc/dealloc. This makes integration with other ownership sources inefficient. For example, adopting pointers from unique_ptr/malloc, or existing class-based implementations would require unnecessary memory traffic to transfer ownership.
If the answer is no, I wonder if it meets the bar for the Standard Library. Since the implementation does not appear to rely on the Builtin module or specialized compiler support, developers could easily implement a tailored version for their specific needs.
I'd prefer a design that abstracts the concept of unique ownership from the specific allocation strategy - via a protocol or a struct that is initializable with a pointer and a deinit handler or both.
I still think UniqueHeapRef is a much more suitable name.
The term Box appears frequently in codebases, but it doesn’t really communicate anything about the semantics or purpose of the type. Why Box specifically – why notBag or Basket?
From a naming perspective, box feels somewhat arbitrary and potentially misleading, since it doesn’t indicate what the type actually represents. Heap and Ref are quite understandable terms in programming, while Box is more of a general English word than a technical concept.
UniqueHeapRef , on the other hand, conveys both key properties: it’s a reference , and the stored value is heap-allocated .
Can someone explain why Box is preferred here over something more descriptive like HeapRef?
I'm generally in favour of having some helper type to provide fixed addresses for instances of value types, but I have reservations about the proposed solution. Specifically, it's unclear to me why the internal storage requires a separate heap allocation.
As somebody adopting this type:
If my calling code is a copyable value type, I cannot use this type directly (because it's ~Copyable) unless I wrap it in an object (which incurs another heap allocation);
If my calling code is a non-copyable value type, I already have storage suitable for containing the underlying value;
If my calling code is a heap-allocated object, I already have storage on the heap for the underlying value;
If my calling code is a global or static value, the compiler is already able to provide it a single static address without a heap allocation;
If my calling code is storing a value of this type on the stack, then since it's ~Copyable it must be moved off the stack in order to escape function scope, in which case a double-allocation is going to be needed.
If the point of the allocation is solely to give the value a stable address, the Swift compiler and runtime have support for providing stable addresses to values allocated locally (for certain definitions thereof) as is used by, for example, _Cell which backs Atomic and Mutex. This type could leverage that support (as an implementation detail, yes) to avoid an extra (i.e. non-zero-cost) heap allocation. The proposal is explicit about using the heap for storage, though.
Edit: If the type only guaranteed a fixed address, but did not specifically state it would be on the heap, that'd be fine, because we could change the implementation in the future to allow for stack promotion or inline storage or some other optimization without violating the API contract.
struct NC: ~Copyable {
let x: Int
let next: NC?
}
error: value type 'NC' cannot have a stored property that recursively contains it
1 | struct NC: ~Copyable {
2 | let x: Int
3 | let next: NC?
| |- error: value type 'NC' cannot have a stored property that recursively contains it
| `- note: cycle beginning here: NC? -> (some(_:): NC)
4 | }
Respectfully, this is a general problem with structures, not just with a box type, right? Enumerations solve this problem with indirect and there's long been some desire from developers for the ability to apply that keyword to stored properties in value types.
I believe you can solve it this way:
struct NC: ~Copyable {
let x: Int
private enum Next: ~Copyable {
case none
indirect case some(NC)
}
let next: NC? {
get { ... } // yielding borrow?
set { ... } // yielding mutate?
}
}
(It's not as ergonomic as an actual indirect keyword for structures, of course.)
Edit: Alas, no, the compiler states "Noncopyable enum 'Next' cannot be marked indirect or have indirect cases yet". Oh well. This can still be solved by, in this narrow use case, manually allocating/deallocating the out-of-band storage.
I would have to see the performance of this prominent API surface permanently hampered by this specific (and, I think, relatively rare) problem.
Anyway, that's my two cents. Again, I am in favour of the overall feature.
I stated this in the pitch, but non copyable enums cannot have indirect cases at the moment. Whether this is a temporary limitation or a permanent one I’m unsure. Optional however, does not have an indirect case. So having to manually create this Next enum every time you need to indirect something means you lose all of the functional utility on Optional like map, flatMap, take, and all of its conformances etc.
Box has been a term of art for a heap allocated value since at least the 1960s. Most Lisp implementations, for instance, store cons cells as either tagged pointers (where the value is stored in the non-tag bits of the pointer), or "boxed" values in dynamically allocated memory.
And more recent examples would include both Java and Objective-C, where storing something like a primitive int in a specialized heap-allocated object (java.lang.Integer or NSNumber, respectively) is referred to as boxing the value.
While the verb forms ( e.g. "boxing" or "boxed") may have been idiomatic for decades, it's not obvious to me that the noun form (Box) has ever been a common term of art.
[How can that be? Because the verb "box" is being used metaphorically, and the rhetoric of metaphors doesn't require that all parts of speech should be analogously metaphorical. Natural language… ]
Heh, this added this pitch link to the mentioned older pitch (in the references at the bottom of the header post), but not vice versa. To do the inverse I'd had to post to that older pitch and revive it which I am hesitant to do – probably it's good to close that one. @ben-cohen maybe you could modify your heading post mentioning the older version.
As for the name: I am not big fan of neither "unique" nor the "box" components of it, but I guess it's just a matter of getting used to it.
not directly relevant for the proposal, but I wonder if/how one could use this for type-erasure wrappers?
class SomeBox<T> is often used in AnyMyThing type-erasures, because you can store it as a base class (or maybe as AnyObject and force-cast later). since UniqueBox<T> (I assume) will have a fixed size no matter the T, is there a elegant, safe-ish way to turn it into an AnyUniqueBox: ~Copyable without classes in the middle that preserve the ownership of the underlying pointer?
Mentioned this briefly in the previous version of this pitch, but worth reiterating here..
We have UnsafePointer.. naturally one would assume that the safe version of it (named Pointer) would be used to describe "safe pointers". There is a certain stigma in the industry about "pointers being unsafe" but that's not (or should not necessarily be) the case in Swift as we explicitly marking unsafe things "unsafe", with safe being the default behaviour.
Is Pointer not the right name for the pitched feature?
Or are we reserving the name Pointer for something more appropriate?