> On Oct 13, 2016, at 10:36 AM, Joe Groff <jgr...@apple.com> wrote:
>> On Oct 11, 2016, at 4:48 PM, Erik Eckstein via swift-dev 
>> <swift-dev@swift.org> wrote:
>> This is a proposal for representing copy-on-write buffers in SIL. Actually 
>> it’s still a draft for a proposal. It also heavily depends on how we move 
>> forward with SIL ownership.
>> <CopyOnWrite.rst>
>> If you have any comments, please let me know.
> The SIL-level design seems sensible to me at a glance. At the language level, 
> I think it would make more sense to treat this as an attribute on class types 
> rather than on properties in structs using the class. I don't think many 
> people reuse class definitions as both shared reference types and as value 
> type payloads, but beyond that, I think that making it an attribute of 
> classes would put us into a better position to leverage the borrow model to 
> enforce the "mutable-only-when-unique" aspect of COW implementations.

I think this makes sense. Although we would need an attribute on the field as 
well (what John called the @copied attribute).

> John alluded to this in the "SIL address types and borrowing" thread:
>> I wonder if it would make more sense to make copy-on-write buffer references 
>> a move-only type, so that as long as you were just working with the raw 
>> reference (as opposed to the CoW aggregate, which would remain copyable) it 
>> wouldn't get implicitly copied anymore.  You could have mutable and 
>> immutable buffer reference types, both move-only, and there could be a 
>> consuming checkUnique operation on the immutable one that, I dunno, returned 
>> an Either of the mutable and immutable versions.
>> For CoW aggregates, you'd need some @copied attribute on the field to make 
>> sure that the CoW attribute was still copyable.  Within the implementation 
>> of the type, though, you would be projecting out the reference immediately, 
>> and thereafter you'd be certain that you were borrowing / moving it around 
>> as appropriate.
> If 'copy-on-write' were a trait on classes, then we could distinguish unique 
> and nonunique references to the class. A unique reference would act like a 
> move-only type to prevent accidental loss of uniqueness. We can also allow a 
> copy-on-write class to have "mutating" methods, and only allow mutation on 
> unique references.

The only way to get a unique reference would then be to use the 
isUnique-builtin - or to create a new buffer. This is good, because we could 
statically check that the programmer can only modify uniquely referenced 
buffers (although to get full memory safety we would probably have  to 
invalidate the original buffer reference between the is_unique - end_unique 
scope, e.g. by storing a null pointer into it).

Thinking about this in detail I believe we have to change how a COW is 
implemented. For example we could not write back the unique reference and use 
it afterwards:

if let uniqueRef = isUnique(&cow.buffer) {
} else {
  uniqueRef = Buffer()
  cow.buffer = uniqueRef // <- this would not work. It’s a copy of a unique 
uniqueRef.someData = ...

Instead this could be done like

if let uniqueRef = isUnique(&cow.buffer) {
} else {
  uniqueRef = Buffer()
uniqueRef.someData = ...
cow.buffer = uniqueRef // OK, end of lifetime of uniqueRef

It would mean that we write back the buffer even in the unique-case, But I 
think this is ok.

For the implementation we would need two different reference types in the AST 
(unique and nonunique), right? Could this be just a different StorageType?

> It seems to me like, exploring this direction, we could also come up with a 
> way for the high-level value-semantics operations on the struct to statically 
> indicate which methods are known to leave the value's buffers in a unique 
> state, or which return values that are uniquely owned, which would give the 
> optimizer more ability to avoid uniqueness checks across calls without 
> relying on inlining and IPO.
> -Joe

swift-dev mailing list

Reply via email to