What The Swift

What Is Any in Swift

What The Swift
1 What Is AnyObject in Swift
2 What Is Any in Swift

Every now and then, I take some time out of my day to explore something about the Swift language that I don't know yet. There's a lot left to explore. I document my findings in a series I named "What The Swift". If you're curious about the more subtle details of the Swift language, then this series is for you.

Last week, we discovered that AnyObject is a protocol defined in the Swift standard library. In today's installment of "What The Swift", I want to show you what Any is. To discover the meaning of Any, we need to revisit the Swift standard library.

Get Ready to Play

Open Xcode and create a new playground. Name the playground What The Swift and set platform to iOS. Tell Xcode where you'd like to save the playground and click Create.

Setting Up the Playground

Revisiting the Swift Standard Library

Clear the contents of the playground and declare a variable, myObject, of type Any.

var myObject: Any

Xcode gives us a clue, but it may not be what you expected. Remember that, last week, we discovered that AnyObject is a protocol. The same doesn't seem to be true for Any. Take a look at the autocompletion menu. The letters Pr show that AnyObject is a protocol. The autocompletion menu is vague about the meaning of Any. It looks like we need to dig a bit deeper.

Any Is Not a Protocol

You know what to do next. Right? Press Command and click Any in the playground to jump to the definition of Any. Hmmm ... do you also see a question mark and hear Xcode's familiar buzz? Why is that? Does this mean Any isn't defined in the Swift standard library?

Any Is Not a Protocol

The Swift Programming Language

Let's take a look at The Swift Programming Language to find out more about Any. In the chapter Type Casting, we find the following.

Any can represent an instance of any type at all, including function types.

That's a start. It tells us that the meaning of Any is broader than that of AnyObject. Any can represent anything hence the name. This also explains why Any isn't a protocol. Even though we know what Any is, I'd like to know more about it. That's the goal of this journey.

Any and id

A Google search brings us to an article on Apple's Swift blog. The title, Objective-C id as Swift Any, is very telling. The article discusses the meaning of Any and AnyObject. More importantly, it explains that the meaning of AnyObject and Any have changed with the release of Swift 3.

In Swift 3, the id type in Objective-C now maps to the Any type in Swift, which describes a value of any type, whether a class, enum, struct, or any other Swift type.

This change improves the compatibility of Swift and Objective-C. Objective-C collections, for example, can hold elements of Any type as of Swift 3. This means that NSArray can store String, Float, and Int instances.

But I want to know more about the why and the how. The article references three Swift Evolution proposals, SE-0072, SE-0116, and SE-0131. It's SE-0116 that looks most promising.

SE-0116

SE-0116 describes in detail the why and the how of this change. The gist is plain and simple. To improve compatibility between Objective-C and Swift, Objective-C's id type maps to Swift's Any type.

In Swift 2, id mapped to AnyObject. While this worked fine, it was far from ideal. Not only did it sometimes result in unexpected behavior, this solution didn't do justice to one of Swift's fundamental concepts, value types. Objective-C and Swift are very different if you take a close look at both languages.

The change introduced by SE-0116 means that it should be possible to bridge any Swift type to an Objective-C object. This isn't a problem for classes and bridged value types, such as Int, String, and the collection types defined by the Swift standard library. But there are plenty of value types that don't have an Objective-C counterpart. These value types are bridged as opaque objects, instances of an immutable class. They are opaque because the name and behavior of these classes are not revealed.

What Is AnyHashable

But there's one problem. Even though Any can represent an instance of any type, it has its limitations. You probably know that the elements of a set and the keys of a dictionary need to be hashable. They need to conform to the Hashable protocol. A set needs the ability to uniquely identify each of the elements it contains. And to look up the value associated with a given key, a dictionary requires its keys to be unique. The problem is that Any doesn't meet this requirement.

As of Swift 3, the Swift standard library defines the AnyHashable supertype. This means that types conforming to the Hashable protocol can be used as AnyHashable. In the Swift standard library, AnyHashable is defined as a struct.

public struct AnyHashable {

    public init<H>(_ base: H) where H : Hashable

    public var base: Any { get }

}

The AnyHashable supertype is used to bring untyped sets and dictionaries from Objective-C to Swift. For example, the userInfo property of Foundation's Notification is of type [AnyHashable : Any].

public struct Notification : ReferenceConvertible, Equatable, Hashable {

    ...

    /// Storage for values or objects related to this notification.
    public var userInfo: [AnyHashable : Any]?

    ...

}

What The Swift

Once you understand the meaning of Any and AnyHashable, much of the mystery disappears. But I hope this article has shown you the value of the Swift Evolution project. Many Swift Evolution proposals are submitted by members of the Swift community, resulting in a better, more robust language.

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By