[swift-evolution] Mutability for Foundation types in Swift

Brent Royal-Gordon brent at architechies.com
Sun Apr 24 05:44:08 CDT 2016

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

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

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

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

>     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

More information about the swift-evolution mailing list