Archive for April 22, 2016

Friday, April 22, 2016

Swift Proposal: Mutability and Foundation Value Types

Tony Parker

As you know from our announcement of Swift Open Source and our work on naming guidelines, one of our goals for Swift 3 is to “drop NS” for Foundation. We want to to make the cross-platform Foundation API that is available as part of swift-corelibs feel like it is not tied to just Darwin targets. We also want to reinforce the idea that new Foundation API must fit in with the language, standard library, and the rapidly evolving design patterns we see in the community.

You challenged us on one part of this plan: some Foundation API just doesn’t “feel Swifty”, and a large part of the reason why is that it often does not have the same value type behavior as other Swift types. 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.

SE-0069:

The pervasive presence of struct types in the standard library, plus the aforementioned automatic bridging of all Cocoa SDK API when imported into Swift, leads to the feeling of an API impedance mismatch for key unbridged Foundation reference types.

[…]

The following value types will be added in the Swift overlay. Immutable/mutable pairs (e.g. Data and MutableData) will become one mutable struct type[…] The overlay is deployed back to the first supported release for Swift, so the implementation of these types will use the existing reference type API.

[…]

Some of the struct types will gain mutating methods. In general, the implementation of the struct type will forward to the underlying reference type, so as to allow a subclass to customize the behavior. If the struct is not initialized with a reference type (using a cast), then it is free to implement as much or as little behavior as it chooses either by delegation to the standard Foundation reference type or via a customized Swift implementation. However, our first version will rely heavily on the existing logic in the Objective-C Foundation framework.

[…]

The most obvious drawback to using a struct is that the type can no longer be subclassed. At first glance, this would seem to prevent the customization of behavior of these types. However, by publicizing the reference type and providing a mechanism to wrap it (mySubclassInstance as ValueType), we enable subclasses to provide customized behavior.

There’s a lot to consider here, but my initial reaction is positive. I don’t fully understand the memory and CPU overhead of the wrapping and bridging yet.

Update (2016-04-25): More about the bridging:

When these types are returned from Objective-C methods, they will be automatically bridged into the equivalent struct type. When these types are passed into Objective-C methods, they will be automatically bridged into the equivalent class type.

[…]

Swift has an existing mechanism to support bridging of Swift struct types to Objective-C reference types. It is used for NSNumber, NSString, NSArray, and more. Although it has some performance limitations (especially around eager copying of collection types), these new struct types will use the same functionality for two reasons:

  1. We do not have block important improvements to our API on the invention of a new bridging system.
  2. If and when the existing bridging system is improved, we will also be able to take advantage of those improvements.

Bridged struct types adopt a compiler-defined protocol called _ObjectiveCBridgeable. This protocol defines methods that convert Swift to Objective-C and vice-versa.

I have written about some bridging performance issues here. The proposal claims:

In almost all API in the SDK, the returned value type is immutable. In these cases, the copy is simply a retain and this operation is cheap. If the returned type is mutable, then we must pay the full cost of the copy.

However, as with the current bridging of string and collection types, it’s not clear what you can do in the event that there is an unwanted copy that affects performance. Likewise, there may be cases where you want to pass references to mutable objects back and forth. In your own Objective-C code, you could probably defeat the bridging by typing the parameters and return values as id, but what about in OS code?

Some interesting posts from the mailing list:

Tony Parker:

In reality, the stored reference object is a Swift class with Swift-native ref counting that implements the methods of the Objective-C NSData “protocol” (the interface described by @interface NSData) by holding a “real” NSMutableData ivar and forwarding messages to it. This technique is actually already in use in the standard library.

[…]

This means that if an Objective-C client calls retain on this object (which is a _SwiftNativeNSData), it actually calls swift_retain, which mutates the Swift ref count. This means that a call to _isUniquelyReferencedNonObjC from Swift actually still works on this class type.

Michael Buckley:

If the answer to this is that the MyMutableData instance is copied in the transfer from Objective-C to Swift so that mutations in Objective-C don’t affect the Swift instance, what about the case where I used var foo instead of let foo? Does that mean that if I modify the data in Objective-C that it won’t get modified in Swift (and vice-versa)?

Brent Royal-Gordon:

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.

Douglas Gregor:

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.

Interestingly, while Swift’s object layout gives us the ability to consider the weak reference count, the Swift runtime currently does not do so. IIRC, part of our reasoning was that isUniquelyReferencedNonObjC is generally there to implement copy-on-write, where weak references aren’t actually interesting. However, we weren’t comfortable enough in that logic to commit to excluding weak references from isUniquelyReferencedNonObjC “forever", and certainly aren’t comfortable enough in that reasoning to enshrine “excluding weak references” as part of the semantics of isUniquelyReference for Objective-C classes.

How iMessage Distributes Security to Block “Phantom Devices”

Rich Mogull:

It turns out you can’t add devices to an iCloud account without triggering an alert because that analysis happens on your device, and doesn’t rely (totally) on a push notification from the server. Apple put the security logic in each device, even though the system still needs a central authority. Basically, they designed the system to not trust them.

[…]

Once in place that will make it impossible to place a ‘tap’ using a phantom device without at least someone in the conversation receiving an alert. The way the current system works, you also cannot add a phantom recipient because your own devices keep checking for new recipients on your account.

I hope he can get Apple to talk about iMessage backups.

iPad Pro, True Tone, and Color Gamut

Craig Hockenberry (tweet):

Over the coming years, displays that only show sRGB are going to feel as antiquated as ones that can only display @1x resolution. And the only way you’re going to be able to cope with all these new kinds viewing environments is with a thing called “color management.”

[…]

We’re quickly reaching a point where more pixels don’t make better photos. Think about how much Apple likes to tout the camera and how better saturation improves photos. These new displays are the first step in a process were wider gamuts become a part of the entire iOS photography workflow. The number of places where your code assumes everything is sRGB will be both surprising and painful.

Jeff Carlson:

If you have a 9.7-inch iPad Pro, you can see the difference for yourself: Craig set up a simple Web page that lets you load the images and compare against sRGB. You should also be able to see it on a 5K iMac, which also uses the same expanded PCI-3 color space, but I haven’t had a chance to view it on one.

The difference is most noticeable in the Harbor photo: Look at the orange streaky reflections in the water at the center of the image and tap the Compare sRGB button. The other images aren’t as noticeable—I have trouble telling the sRGB differences, probably because the gamut is most pronounced at the red/orange end of the spectrum.

Update (2016-04-22): Craig Hockenberry:

This is clearly a time where our tools and APIs need to evolve. Here are some things that you’ll need to watch out for as you start using color management on iOS[…]

Bots Won’t Replace Apps

Dan Grover:

This recent “bot-mania” is at the confluence of two separate trends. One is agent AIs steadily getting better, as evidenced by Siri and Alexa being things people actually use rather than gimmicks. The other is that the the US somehow still hasn’t got a dominant messaging app and Silicon Valley is trying to learn from the success of Asian messenger apps. This involves a peculiar fixation on how these apps, particularly WeChat, incorporate all sorts of functionality seemingly unrelated to messaging. They come away surprised by just how many differently-shaped pegs fit into this seemingly oddly-shaped hole. The thesis, then, is that users will engage more frequently, deeply, and efficiently with third-party services if they’re presented in a conversational UI instead of a separate native app.

[…]

As I’ll explain, messenger apps’ apparent success in fulfilling such a surprising array of tasks does not owe to the triumph of “conversational UI.” What they’ve achieved can be much more instructively framed as an adept exploitation of Silicon Valley phone OS makers’ growing failure to fully serve users’ needs, particularly in other parts of the world. Chat apps have responded by evolving into “meta-platforms.” Many of the platform-like aspects they’ve taken on to plaster over gaps in the OS actually have little to do with the core chat functionality. Not only is “conversational UI” a red herring, but as we look more closely, we’ll can even see places where conversational UI has breached its limits and broken down.

[…]

I want the first tab of my OS’s home screen to be a central inbox half as good as my chat app’s inbox. It want it to incorporate all my messengers, emails, news subscriptions, and notifications and give me as great a degree of control in managing it.

“It Just Works” Should Be the Next Step

Riccardo Mori:

In the end, I think that what the next ‘MacOS’ needs most is focus. Focus on what it has historically done best — ‘just working’. I don’t think that the current problems of OS X have much to do with its old age or its old models. It’s more a matter of identity. I feel that recent versions of OS X have tried to ‘look friendly’, as if to say Hey folks, I can be simple like iOS! Look, I too can have big app icons taking up the whole screen! I too can go full-screen with apps, and I can do split-view just as well! And I have Notification Centre like on iOS! and so on. This path of convergence with iOS hasn’t been all bad, but the process has involved an accumulation of new features which not always have brought more value or functionality, and often have introduced bugs or annoyances; all this has ultimately undermined the most important aspect of using a Mac — the ‘it just works’ aspect.