[swift-evolution] Mutability for Foundation types in Swift

Tony Parker anthony.parker at apple.com
Mon Apr 25 11:20:40 CDT 2016


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 <brent at architechies.com> 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.

Agreed, that is why they are at the bottom in the “not value types” section. =)

> (I also see little value in an Error type; honestly, in the long run I'd like to see Swift-facing Foundation grow towards pretending that NSError doesn't exist and only ErrorProtocol does.)
> 

ErrorProtocol is a kind-of-NSError today, as the compiler magically generates the two NSError primitives for you (code and domain), but does not expose this anywhere to make it possible to do the correct thing w.r.t. localized error messages.

Anyway this is a complicated topic, which is why I deferred it to another proposal.

>> The following code is a more natural match for the way Swift developers would expect this to work:
>> 
>> 	var myDate = Date()
>> 	myDate.addTimeInterval(60) // OK
>> 	
>> 	let myOtherDate = Date()
>> 	myOtherDate.addTimeInterval(60) // Error, as expected
> 
> The semantic is definitely more what Swift users expect, but the name may not be. As far as I can tell, this method should be called `add`, with `TimeInterval` elided under the "omit needless words" rule of Swift API translation. (Or just call it `+=`, of course…)

The actual API uses +=, this is just an example to prove a point.

> 
>> URL		NSURL
>> URLComponents	NSURLComponents
> 
> 
> Have you considered unifying these? NSURL has no mutable counterpart, but NSURLComponents sort of informally plays that role. As it is, it seems like URL would not really be able to support mutation very well—the operations would all be nonmutating under the hood.
> 

The pattern here is that URLComponents properties are basically the arguments to a factory that creates URL. They aren’t really the same thing as a URL itself. Also, like DateComponents or PersonNameComponents, you may want to represent a “partial URL” as some kind of intermediate object, in which case a URLComponents would be the right type because a URL should be valid.

>> Using Swift structures for our smallest types can be as effective as using tagged pointers in Objective-C.
> 
> 
> Have you looked at the performance and size of your value type designs when they're made Optional? In the general case, Optional works by adding a tag byte after the wrapped instance, but for reference types it uses the 0x0 address instead. Thus, depending on how they're designed and where Swift is clever enough to find memory savings, these value types might end up taking more memory than the corresponding reference types when made Optional, particularly if the reference types have tagged pointer representations.
> 

That’s true, but not all reference types wind up as tagged pointers either. NSString, for example, does it based on the content and length of the C string.

I’m ok with the tradeoff here for the few types we have in this category (primarily Date).

>>    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.

- Tony





More information about the swift-evolution mailing list