[swift-evolution] [Pitch] Rename `AnyObject` to `AnyClass` and drop current `AnyClass`

Brent Royal-Gordon brent at architechies.com
Fri May 20 19:40:52 CDT 2016

> The Any-class requirement could replace the current `AnyObject` protocol with a typealias like this: `typealias AnyObject = Any<class>`
> Assume Swift would introduce Any-struct and Any-enum requirement one day. How would one name a typealias for these, where `AnyClass` means `AnyObject.Type`?
> I suggest we drop the current `AnyClass` and rename `AnyObject` to `AnyClass`. If one would need the old `AnyClass` behavior it will become `AnyClass.Type`.

I propose that we deprecate `AnyObject` in favor of `Any<class>`. No typealias, just directly using `Any<>`. We would also deprecate `AnyClass` in favor of `Any<class>.Type`. (Presumably we would do this by providing `AnyObject` and `AnyClass` typealiases in Swift 3, but marking them as deprecated.)

I like this approach because it exposes people to `Any<>` and more quickly gets them to see how it's connected to a protocol declaration's conformance list. They might then guess that `Any<>` has other capabilities from that list, like the ability to handle multiple protocols.

> In the future we could have typealiases like this, which are more clear:
> `typealias AnyClass = Any<class>`
> `typealias AnyStruct = Any<struct>`
> `typealias AnyEnum = Any<enum>`

Even in the long term, I don't see any good reason to support `Any<struct>` vs. `Any<enum>`. There is no semantic distinction* between a struct and an enum; you can always implement something enum-y using a struct with a mode field, or something struct-y using an enum with associated values. `Bool`, for instance, was once an enum and was changed to a struct for implementation reasons; this change made no difference to how it was used.

Now, there *is* a semantic distinction between struct/enum and class—one is a value type, the other is a reference type. To support that distinction, it might make sense to support an `Any<value>` or `Any<!class>` syntax. Again, I would prefer to use the raw `Any<>` syntax, though, not a typealias.

(I've read the arguments about pure vs. non-pure value type conformances and I'm not convinced. It is always possible to nominally "conform" to a protocol in a way that actually undermines its guarantees; for example, you could implement `RangeReplaceableCollection.remove(at:)` as a no-op. The compiler cannot reject all invalid conformances; it can only reject ones which it can trivially show are invalid, because for instance they do not even attempt to provide a required method. Similarly, the compiler may not be able to prove you are providing value semantics, but it *can* reject conformances of reference types to a protocol requiring value semantics, since those cannot possibly be valid conformances.

Incidentally, I am not convinced that it *ever* makes sense to have a mutating protocol which does not specify either value or reference semantics. The only intentional Stdlib examples I'm aware of are `IteratorProtocol` and `OutputStream`, and I think both of those should be reference-only.

(On the other hand, it might make sense to be able to mark a struct or enum as "this is actually a reference type". For instance, if you import libc, UnsafeMutablePointer<FILE> is essentially a reference type. But on the gripping hand, you *could*, and perhaps should, just wrap it in a class, either through importer magic or a manually-created type. That would permit you to conform it to reference-typed mutating protocols.))

* There *are* some distinctions, particularly in pattern matching, but protocols can't model them anyway. Incidentally, it is not possible to satisfy static property/method requirements with cases, but it probably should be:

    protocol OptionalProtocol { 
        associatedtype W
        static var none: Self { get } 
        static func some(value: W) -> Self 
    extension Optional: OptionalProtocol {
        typealias W = Wrapped

Brent Royal-Gordon

More information about the swift-evolution mailing list