What The Swift

What Is Any in Swift

What The Swift
1 What Is AnyObject in Swift 06:10
2 What Is Any in Swift 05:56

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.

Earlier this 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 and create a new playground. Choose the Blank template from the iOS section.

Setting Up the Playground

Name the playground What The Swift, 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

This time Xcode doesn't give us a clue as to the meaning of Any. Earlier this week, we found out that AnyObject is a protocol. The same doesn't seem to be true for Any. Xcode's autocompletion menu shows that AnyObject is a protocol.

AnyObject is a protocol.

The documentation is vague about the meaning of Any. It looks like we need to dig a bit deeper.

Any is not a protocol.

Press Command and click Any in the playground to jump to the definition of Any. This worked fine for AnyObject, but it doesn't seem to work for Any. Does this mean that Any isn't defined in the Swift standard library?

The Swift Programming Language

Let's take a look at The Swift Programming Language to find out more about Any. In the chapter titled 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 episode.

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 Foundation's NSArray type 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 the compatibility of 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, the 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 type 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. I hope this episode has also 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