> On Apr 25, 2016, at 10:32 AM, Douglas Gregor via swift-evolution 
> <[email protected]> wrote:
>> On Apr 25, 2016, at 9:20 AM, Tony Parker via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>> Hi Brent,
>> 
>> Thanks for your feedback! You’ve got some great questions below, I’ll try to 
>> answer them as best I can.
>> 
>>> On Apr 24, 2016, at 3:44 AM, Brent Royal-Gordon <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>>> We took this feedback seriously, and I would like to share with you the 
>>>> start of an important journey for some of the most commonly used APIs on 
>>>> all of our platforms: adopting value semantics for key Foundation types.
>>> 
>>> This proposal is way cool, and I think you've selected a great starting set 
>>> of APIs.
>>> 
>>> Of the other candidate APIs you mentioned, I'm definitely looking forward 
>>> to AttributedString and some parts of the NSURL Loading system (primarily 
>>> the requests and responses; the connections and sessions should probably be 
>>> object types). Predicate, OrderedSet, CountedSet, and possibly Number and 
>>> Value make sense as well.
>>> 
>>> However, I think that Locale, Progress, Operation, Calendar, and Port are 
>>> poor candidates for becoming value types, because they represent specific 
>>> resources which may be partially outside of your thread's/process's 
>>> control; that is, they're rather like NS/UIView, in that they represent a 
>>> specific, identifiable "thing" which cannot be copied without losing some 
>>> aspect of its meaning.
>> 
>>>>   if !isUniquelyReferencedNonObjC(&_box) {
>>> 
>>> 
>>> Something I have often wondered about: Why doesn't 
>>> `isUniquelyReferenced(_:)` use `-retainCount` on Objective-C objects? 
>>> Alternatively, why not use `-retainCount` on fields in your value types 
>>> when you're trying to implement COW behavior? It seems like that would 
>>> allow you to extend the copy-on-write mechanism to Objective-C objects. I 
>>> know that `-retainCount` is usually not very useful, but surely this 
>>> copy-on-write situation, where you are using it in an advisory fashion and 
>>> an overestimated retain count will simply cause you to unnecessarily lose 
>>> some efficiency, is the exception to the rule?
>>> 
>>> There are likely good reasons for this decision—they simply aren't obvious, 
>>> and I'd like to understand them.
>>> 
>>> -- 
>>> Brent Royal-Gordon
>>> Architechies
>>> 
>> 
>> There are a few reasons for this, but the one that sticks out most to me is 
>> that in Objective-C, retain, release, and retainCount don’t include weak 
>> references. If you take a look at the internals for the swift retain count 
>> function, you’ll see that there are two: owned and unowned.
> 
> 
> Right. I went down this rabbit hole a few weeks ago, trying to determine if 
> we could make an “isUniquelyReferenced” that works for Objective-C-defined 
> classes. One obvious issue is that you can’t always trust retainCount to do 
> the right thing for an arbitrary Objective-C class, because it may have been 
> overridden. We can probably say “don’t do that” and get away with it, but 
> that brings us to Tony’s point: Objective-C weak references are stored in a 
> separate side table, so we can’t atomically determine whether an Objective-C 
> class is uniquely referenced. On platforms that have a non-pointer “isa” we 
> could make this work through the inline reference count (which requires 
> changes to the Objective-C runtime and therefore wouldn’t support backward 
> deployment), but that still doesn’t give us “isUniquelyReferenced” for 
> Objective-C classes everywhere.

It's arguably not necessary to do this check atomically with respect to 
concurrent attempts to retain/release:
  - If somebody is racing to increase the reference count to 2, they must be 
copying this variable.
  - If somebody is racing to increase the reference count to > 2, our reference 
is non-unique either way.
  - If somebody is racing to decrease the reference count to 1, then we either 
do an over-safe copy or we get lucky avoiding it.
  - If somebody is racing to decrease the reference count to 1, they must be 
mutating this variable.
We only do this uniqueness check when mutating the variable, so a concurrent 
attempt to copy or mutate it is an illegal read/write or write/write race.

Weak references are potentially a different story, both semantically and in 
terms of concurrency.  There could be an outstanding weak reference that 
somebody could be concurrently loading (and hence retaining), breaking the 
assumption in the first bullet above.  The only way to fix that is to treat 
weak references as making strong references non-unique, and AFAIK we have no 
way of detecting the non-existence of weak references on existing operating 
systems.  But it's not clear to me that we need to give this much weight to 
weak references; after all, it's equally possible to form unsafe references to 
existing objects, which is completely undetectable, and we've traditionally 
described that as just an unsafe weak reference.

You have to come up with fairly contrived use cases for weak references to see 
problems with just ignoring them, like a memoization table that maintains both 
strong and weak references but drops the strong references when there's memory 
pressure.  In this case, our value type might end up with the last strong 
reference, and changing the object in-place would corrupt the cached value.  
But this would be a really odd way to implement a memoization table, basically 
just using weak references for their own sake.

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

Reply via email to