Thanks Doug, I’m writing a proposal about it.

- Torin

> On 31 Jan 2017, at 07:20, Douglas Gregor <dgre...@apple.com> wrote:
> 
> 
>> On Jan 28, 2017, at 10:43 PM, Rod Brown via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> I agree that there is an issue here.
>> 
>> While I understand that the initialiser avoids the full setter for direct 
>> access, I would expect the attribute to mean that the substituted direct 
>> access still applied the attribute you marked the API with. I would consider 
>> the fact that it doesn't work as a dangerous gap in the API.
>> 
>> It is also concerning if we consider how this will work with Property 
>> Behaviours that are planned for Swift in the future. If we made NSCopying a 
>> property behaviour, the direct access would mean it too would not be invoked 
>> at initial access so I'm not sure how the best way to get around this is - 
>> should we do compiler magic to copy in the initialiser, or should we warn if 
>> we don't detect a call to copy() or copy(with:) in the initialiser?
> 
> I think we should be doing the compiler magic to call copy(with:) in the 
> initializer, because that seems like the most direct way to maintain the 
> @NSCopying contract without changing the underlying direct-storage model.
> 
>> I think we at least need to do something here. It's a very convoluted piece 
>> of logic to say the @NSCopying attribute doesn't work in an initialiser and 
>> it's hardly intuitive despite the fair reasoning.
> 
> I agree that we need to do something here. It feels like it’s just a bug—that 
> this is the only way that @NSCopying makes sense in an attribute. Might even 
> be a good starter bug for someone who wants to dip their tows into the type 
> checker!
> 
>       - Doug
> 
>> 
>> Rod
>> 
>>> On 29 Jan 2017, at 4:47 pm, Torin Kwok via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>>> 
>>> Yep, I also admit the design of forbidding calling a setter before full
>>> class initialization is reasonable and what's really annoying is the
>>> inconsistency.
>>> 
>>> However, making @NSCopying attribute not subjects to the fact that
>>> setters would not be invoked in initializers perhaps is viable too. In
>>> the other words, assigning a value to a property whether or not by
>>> calling a setter has no influence on whether @NSCopying semantic'd work:
>>> copying should always take place after a property has been declared as
>>> @NSCopying.
>>> 
>>> Jean-Daniel writes:
>>> 
>>>>> Le 28 janv. 2017 à 05:34, Torin Kwok via swift-evolution 
>>>>> <swift-evolution@swift.org> a écrit :
>>>>> 
>>>>> Hello guys,
>>>>> 
>>>>> Note: This issue has been originally presented inswift-usersmailling list 
>>>>> <https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004552.html>.
>>>>>  And then I post it again here at the suggestion 
>>>>> <https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004561.html>
>>>>>  of Jordan Rose:
>>>>> 
>>>>> It might be reasonable to change this behavior, but it probably deserves 
>>>>> a bit of discussion on swift-evolution; it's not 100%, for-sure a bug.
>>>>> --- the original content follows this line ---
>>>>> 
>>>>> I encountered a strange behavior when I declared a property with the 
>>>>> @NSCopying attribute:
>>>>> 
>>>>> // `Person` class inherits from `NSObject` class and conforms to 
>>>>> `NSCopying` protocol
>>>>> @NSCopying var employee: Person
>>>>> and then assigned an external instance of Person class protocol to this 
>>>>> property within the designated init methods:
>>>>> 
>>>>> // Designated initializer of `Department` class
>>>>> init( employee externalEmployee: Person ) {
>>>>> self.employee = externalEmployee
>>>>> super.init()
>>>>> 
>>>>> // Assertion would fail since Swift do not actually copy the value 
>>>>> assigned to this property         
>>>>> // even though `self.employee` has been marked as `@NSCoyping`
>>>>> // assert( self.employee !== externalEmployee )
>>>>> }
>>>>> If I indeed require the deep copying behavior during the init process, 
>>>>> instead of taking advantage of @NSCopying attribute, I would have to 
>>>>> invoke the copy() method manually:
>>>>> 
>>>>> init( employee externalEmployee: Person ) {
>>>>> // ...
>>>>> self.employee = externalEmployee.copy() as! Person  
>>>>> // ...
>>>>> }
>>>>> In fact, what really makes me confusing is that @NSCopying semantic does 
>>>>> work properly within the other parts of the class definition such as 
>>>>> normal instance methods, or external scope. For instance, if we're 
>>>>> assigning an external instance of Person to the self.employee proper of 
>>>>> Department directly through setter rather than initializer:
>>>>> 
>>>>> department.employee = johnAppleseed
>>>>> then self.employee property and johnAppleseed variable will no longer 
>>>>> share the same underlying object now. In the other words, @NSCopying 
>>>>> attribute makes sense.
>>>>> 
>>>>> After I looked through a great deal of results given by Google, and 
>>>>> dicussions on StackOverflow, I finally end up with nothing helpful — the 
>>>>> vast majority of articles, documentations as well as issues talking about 
>>>>> this similar topics only focus on the basic concepts and effects of 
>>>>> @NSCopying itself but do not mentioned this strange behavior at all — 
>>>>> besides one radar descriping the same problem (rdar://21383959 
>>>>> <rdar://21383959>) and a final conclusion mentioned in a guy's Gist 
>>>>> comment: ... values set during initialization are not cloned ...
>>>>> 
>>>>> That is, @NSCopying semantic has no effect in initializers.
>>>>> 
>>>>> Then, what I want to figure out is the reason why @NSCopying semantic 
>>>>> will become effectless implicitly whithin initializers of a class, and 
>>>>> the special considerations behind this behavior, if any.
>>>>> 
>>>>> --- END ---
>>>>> 
>>>>> Jordan:
>>>>> 
>>>>> Your observation is correct: @NSCopying currently does not affect 
>>>>> initializers. This is because accessing a property in an initializer 
>>>>> always does direct access to the storage rather than going through the 
>>>>> setter.
>>>>> I have tested the identical logic in Objective-C and the NSCopying 
>>>>> semantic works perfectly within Obj-C's class initializer.
>>>>> 
>>>> This is because Obj-C guarantee that all ivars are zero initialized and 
>>>> does not enforce initializer safety (but forcing initialization of ivars 
>>>> before calling other methods).
>>>> 
>>>> Calling a setter (like any other method) before full class initialization 
>>>> is unsafe as the setter may be overridden or simply customized, and may 
>>>> need to access to the class or subclasses ivars.
>>>> 
>>>> That said, I’m not sure what is the best way to solve that inconsistency.
>>> 
>>> 
>>> -- 
>>> Torin Kwok (郭桐)
>>> OpenPGP/GnuPG: https://keybase.io/kwok
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 

Attachment: smime.p7s
Description: S/MIME cryptographic signature

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to