Hehe :-)

I’ll hold off suggestions until we need to cross that road!

- Alex

> On Mar 15, 2016, at 6:28 PM, Arnold <[email protected]> wrote:
> 
> Hi Alex,
> 
> Probably not, The name is a strawman. I guess I could not resist the 
> optimizer speak after all. The programmer is asserting he guarantees the 
> lifetime by other means. I expect if this proposal moves forward the standard 
> library team will decide on the right name for this method.
> 
> assertLifetimeGuarantee, withAssertedLifetime, 
> unsafePassWithAssertedLifetime, ... ?
> 
> 
> 
> On Mar 15, 2016, at 6:14 PM, Alex Migicovsky <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> Hi Arnold,
>> 
>> This seems like a great optimization tool. The only question I have is about 
>> the method name. With the name `withUnsafeGuaranteedValue` we’re moving the 
>> term “guaranteed” into API in addition to it being an implementation detail 
>> of the compiler as far as I could tell. Is “guaranteed" the best name for 
>> this?
>> 
>> - Alex
>> 
>>> On Mar 15, 2016, at 6:01 PM, Arnold Schwaighofer via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>> 
>>> Updated proposal: use a method that accepts a closure to delineate the 
>>> required guaranteed lifetime for which the assertion by the programmer 
>>> holds.
>>> And, hopefully, no optimizer language speak.
>>> 
>>> 
>>> Add an API to Unmanaged to get the instance it holds @guaranteed
>>> 
>>> Proposal: SE-0000 Add an API to Unmanaged to get the instance it holds 
>>> guaranteed 
>>> <https://github.com/aschwaighofer/swift-evolution/blob/unmanaged_unsafe_guaranteed_proposal/proposals/0000-unsafe-guaranteed.md>
>>> Author(s): Arnold Schwaighofer <https://github.com/aschwaighofer>
>>> Status: Draft
>>> Review manager: TBD
>>>  
>>> <https://github.com/aschwaighofer/swift-evolution/blob/unmanaged_unsafe_guaranteed_proposal/proposals/0000-unsafe-guaranteed.md#introduction>Introduction
>>> 
>>> The standard library Unmanged<Instance> struct provides an instance wrapper 
>>> that does not participate in ARC; it allows the user to make manual 
>>> retain/release calls and get at the contained instance at 
>>> balanced/unbalanced retain counts.
>>> 
>>> This proposal suggests to add another method withUnsafeGuaranteedValue to 
>>> Unmanaged that accepts a closure. Calling this method is akin to making an 
>>> assertion about the guaranteed lifetime of the instance for the delinated 
>>> scope of the method invocation. The closure is passed the unmanaged 
>>> reference as a managed reference.
>>> 
>>>   func doSomething(u : Unmanged<Owned>) {
>>>     // The programmer asserts that there exists another managed reference 
>>> of the
>>>     // unmanaged reference stored in 'u' and that the lifetime of the 
>>> referenced
>>>     // instance is guaranteed to extend beyond the 
>>> 'withUnsafeGuaranteedValue'
>>>     // invocation.
>>>     u.withUnsafeGuaranteedValue {
>>>       $0.doSomething()
>>>     }
>>>   }
>>> This assertion will help the compiler remove ARC operations.
>>> 
>>> public struct Unmanaged<Instance : AnyObject> {
>>> 
>>>   // Get the value of the unmanaged referenced as a managed reference 
>>> without
>>>   // consuming an unbalanced retain of it and pass it to the closure. 
>>> Asserts
>>>   // that there is some other reference ('the owning reference') to the
>>>   // unmanaged reference that guarantees the lifetime of the unmanaged 
>>> reference
>>>   // for the duration of the 'withUnsafeGuaranteedValue' call.
>>>   //
>>>   // NOTE: You are responsible for ensuring this by making the owning 
>>> reference's
>>>   // lifetime fixed for the duration of the 'withUnsafeGuaranteedValue' 
>>> call.
>>>   //
>>>   // Violation of this will incur undefined behavior.
>>>   //
>>>   // A lifetime of a reference 'the instance' is fixed over a point in the
>>>   // programm if:
>>>   //
>>>   // * There is another managed reference to the same instance 'the 
>>> instance'
>>>   //   whose life time is fixed over the point in the program by means of
>>>   //  'withExtendedLifetime' closing over this point.
>>>   //
>>>   //   var owningReference = Instance()
>>>   //   ...
>>>   //   withExtendedLifetime(owningReference) {
>>>   //       point($0)
>>>   //   }
>>>   //
>>>   // Or if:
>>>   //
>>>   // * There is a class, or struct instance ('owner') whose lifetime is 
>>> fixed at
>>>   //   the point and which has a stored property that references 'the 
>>> instance'
>>>   //   for the duration of the fixed lifetime of the 'owner'.
>>>   //
>>>   //  class Owned {
>>>   //  }
>>>   //
>>>   //  class Owner {
>>>   //    final var owned : Owned
>>>   //
>>>   //    func foo() {
>>>   //        withExtendedLifetime(self) {
>>>   //            doSomething(...)
>>>   //        } // Assuming: No stores to owned occur for the dynamic 
>>> lifetime of
>>>   //          //           the withExtendedLifetime invocation.
>>>   //    }
>>>   //
>>>   //    func doSomething() {
>>>   //       // both 'self' and 'owned''s lifetime is fixed over this point.
>>>   //       point(self, owned)
>>>   //    }
>>>   //  }
>>>   //
>>>   // The last rule applies transitively through a chains of stored 
>>> references
>>>   // and nested structs.
>>>   //
>>>   // Examples:
>>>   //
>>>   //   var owningReference = Instance()
>>>   //   ...
>>>   //   withExtendedLifetime(owningReference) {
>>>   //     let u = Unmanaged.passUnretained(owningReference)
>>>   //     for i in 0 ..< 100 {
>>>   //       u.withUnsafeGuaranteedValue {
>>>   //         $0.doSomething()
>>>   //       }
>>>   //     }
>>>   //   }
>>>   //
>>>   //  class Owner {
>>>   //    final var owned : Owned
>>>   //
>>>   //    func foo() {
>>>   //        withExtendedLifetime(self) {
>>>   //            doSomething(Unmanaged.passUnretained(owned))
>>>   //        }
>>>   //    }
>>>   //
>>>   //    func doSomething(u : Unmanged<Owned>) {
>>>   //      u.withUnsafeGuaranteedValue {
>>>   //        $0.doSomething()
>>>   //      }
>>>   //    }
>>>   //  }
>>>   public func withUnsafeGuaranteedValue<Result>(
>>>     @noescape closure: (Instance) throws -> Result
>>>   ) rethrows {
>>>     let instance = _value
>>>     let (guaranteedInstance, token) = Builtin.unsafeGuaranteed(instance)
>>>     try closure(guaranteedInstance)
>>>     Builtin.unsafeGuaranteedEnd(token)
>>>   }
>>> Prototype: link to a prototype implementation 
>>> <https://github.com/aschwaighofer/swift/tree/unsafe_guaranteed_prototype>
>>>  
>>> <https://github.com/aschwaighofer/swift-evolution/blob/unmanaged_unsafe_guaranteed_proposal/proposals/0000-unsafe-guaranteed.md#motivation>Motivation
>>> 
>>> A user can often make assertions that an instance is kept alive by another 
>>> reference to it for the duration of some scope.
>>> 
>>> Consider the following example:
>>> 
>>> class Owned {
>>>   func doSomeWork() {}
>>> }
>>> 
>>> public class Owner {
>>>   var ref: Owned
>>> 
>>>   init() { ref = Owned() }
>>> 
>>>   public func doWork() {
>>>     withExtendedLifetime(self) {
>>>       doSomething(ref)
>>>     }
>>>   }
>>> 
>>>   func doSomething(o: Owned) {
>>>      o.doSomeWork()
>>>   }
>>> }
>>> In this context the lifetime of Owner always exceeds o: Ownee. However, 
>>> there is currently no way to tell the compiler about such an assertion. We 
>>> can pass reference counted values in an Unmanged container without 
>>> incurring reference count changes.
>>> 
>>> public class Owner {
>>> 
>>>   public func doWork() {
>>>     // No reference count for passing the parameter.
>>>     doSomething(Unmanaged.passUnretained(ref))
>>>   }
>>> 
>>>   func doSomething(u: Unmanaged<Owned>) {
>>>     // ...
>>>   }
>>> }
>>> We can get at the contained instance by means of takeUnretainedValue() 
>>> which will return a balanced retained value: the value is returned at +1 
>>> for release by the caller. However, when it comes to accessing the 
>>> contained instance we incur reference counting.
>>> 
>>>   func doSomething(u: Unmanaged<Owned>) {
>>>     // Incurs refcount increment before the call and decrement after for 
>>> self.
>>>     u.takeUnretainedValue().doSomeWork()
>>>   }
>>> With the proposed API call the user could make the assertion that u's 
>>> contained instance's lifetime is guaranteed by another reference to it.
>>> 
>>>   func doSomething(u: Unmanaged<Owned>) {
>>>     // Incurs refcount increment before the call and decrement after for 
>>> self
>>>     // that can be removed by the compiler based on the assertion made.
>>>     u.withUnsafeGuaranteedValue {
>>>       $0.doSomeWork()
>>>     }
>>>   }
>>> The compiler can easily remove the reference counts marked by this method 
>>> call with local reasoning.
>>> 
>>>  
>>> <https://github.com/aschwaighofer/swift-evolution/blob/unmanaged_unsafe_guaranteed_proposal/proposals/0000-unsafe-guaranteed.md#impact-on-existing-code>Impact
>>>  on existing code
>>> 
>>> This is a new API that does not replace an existing method. No existing 
>>> code should be affected.
>>> 
>>>  
>>> <https://github.com/aschwaighofer/swift-evolution/blob/unmanaged_unsafe_guaranteed_proposal/proposals/0000-unsafe-guaranteed.md#alternatives-considered>Alternatives
>>>  considered
>>> 
>>> A somewhat related proposal would be to allow for class types to completely 
>>> opt out of ARC forcing the programmer to perform manual reference counting. 
>>> The scope of such a proposal would be much bigger making it questionable 
>>> for Swift 3 inclusion. I believe that the two approaches are complementary 
>>> and don't completely supplant each other. This proposal's approach allows 
>>> for selectively opting out of ARC while providing a high notational burdon 
>>> when wide spread over the application (wrapping and unwrapping of 
>>> Unmanaged). Opting completely out of ARC is an all-in solution, which on 
>>> the other hand does not have the high notational burden.
>>> 
>>> 
>>>> On Mar 15, 2016, at 4:06 PM, Dave Abrahams <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>> 
>>>> 
>>>> on Mon Mar 14 2016, John McCall <rjmccall-AT-apple.com 
>>>> <http://rjmccall-at-apple.com/>> wrote:
>>>> 
>>>>>> In this example this would be for the lifetime for the value in x which 
>>>>>> extends to the lifetime of y.
>>>>> 
>>>>> What if I return it or assign it to non-local memory?
>>>>> 
>>>>> I feel like you’re trying to define this by optimizer behavior.
>>>>> That’s not a workable language rule; programmers are not going to
>>>>> reason about SSA values.
>>>> 
>>>> Thank you, John.  That is the problem I usually have with evaluating
>>>> most optimizer proposals.
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected] <mailto:[email protected]>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to