> On Jan 28, 2017, at 10:43 PM, Rod Brown via swift-evolution 
> <[email protected]> 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 
>> <[email protected]> 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 
>>>> <[email protected]> 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
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> 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