> 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