[Pitch] Rename `AnyObject` to `AnyClass` and drop current `AnyClass`


(Adrian Zubarev) #1

I’d like to discuss with the community to see their reactions on that topic.

Basically from the beginning of Swift I thought it was just confusing how these typealiases were used and named.
As we know from Apply API Guidelines to the Standard Library the Type suffix will be dropped.

Currently we also discuss about the `Any<…>` existential which may contain Any-type requirement one day (by ’type’ I mean `class`, `struct`, `enum` in a way like this: `Any<class>`).

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

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

I don’t know how the migration process works but I can assume that this should be done in the right order:

- migrate every `AnyClass` to `AnyClass.Type`
- at the end migrate `AnyObject` to `AnyClass`

What do you think? I’d write a small proposal if the community reaction is positive.

···

--
Adrian Zubarev
Sent with Airmail


(Brent Royal-Gordon) #2

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
Architechies


(Dave Abrahams) #3

I’d like to discuss with the community to see their reactions on that topic.

Basically from the beginning of Swift I thought it was just confusing how these typealiases were used and named.
As we know from Apply API Guidelines to the Standard Library the Type suffix will be dropped.

Currently we also discuss about the `Any<…>` existential which may
contain Any-type requirement one day (by ’type’ I mean `class`,
`struct`, `enum` in a way like this: `Any<class>`).

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

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

I would oppose this, since the distinction between AnyStruct and AnyEnum
is not a useful one. There's no observable semantic difference between
a struct that conforms to a protocol P and an enum that conforms to the
same protocol.

···

on Fri May 20 2016, Adrian Zubarev <swift-evolution@swift.org> wrote:

I don’t know how the migration process works but I can assume that this should be done in the right order:

- migrate every `AnyClass` to `AnyClass.Type`
- at the end migrate `AnyObject` to `AnyClass`

What do you think? I’d write a small proposal if the community reaction is positive.

--
Adrian Zubarev
Sent with Airmail
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave


(Matthew Johnson) #4

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.

You can implement reference types with value semantics and value types with reference semantics. Until the compiler can verify value semantics I am not sure there is a benefit to `any<value>`. The semantic distinction is what is important. There has been discussion about strengthening the “value type == value semantics” and “reference type == reference semantics” relations but that hasn’t yet moved beyond talk.

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

Immutable reference types actually *can* provide valid value semantics (at least as long as as they can provide their own implementation of `==` which I believe Dave A is arguing against).

There is a big difference between semantics that the compiler *could* but *does not yet* verify and semantics that simply cannot be verified.

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

This is a good example of why the semantics aren’t so simple.

* 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
   }

I think there was discussion at some point about introducing enum case requirements into protocols. But that is mostly tangential to this discussion.

···

On May 20, 2016, at 7:40 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Patrick Smith) #5

Straight Any<class> sounds good to me. Otherwise keep it at AnyObject. Renaming it to AnyClass does not seem right, especially as there already is one present in Swift 2 with the different meaning.

···

On 21 May 2016, at 10:40 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

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
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #6

You can implement reference types with value semantics and value types with reference semantics.

Immutable reference types actually *can* provide valid value semantics (at least as long as as they can provide their own implementation of `==` which I believe Dave A is arguing against).

Not in the sense I mean—that is, not if the protocol has members which require you to mutate self.

If a reference type is immutable, you can treat it like a value type. But then it can't correctly conform to a protocol (like `RangeReplaceableCollection`) with mutating members, because it is *immutable*. It would have to take `self` as an `inout` parameter and replace `self` with a copy, but methods on classes cannot take `self` as an inout parameter. It's stuck.

In other words, there are three sensible types of protocols:

1. Protocols that do not require any self-mutating members, and do not assume either value or reference semantics.
2. Protocols that require self-mutating members, and assume value semantics.
3. Protocols that require self-mutating members, and assume reference semantics.

However, what Swift actually supports is:

1. Protocols that do not require any self-mutating members, and do not assume either value or reference semantics.
2. Protocols that require self-mutating members, and can be implemented by either classes or structs/enums.
3. Protocols that require self-mutating members, and must be implemented by classes.

The mismatch in #2 (between assuming value semantics and allowing classes to conform) is one source of mischief: the compiler does nothing to help you realize that you cannot possibly correctly conform a class to the protocol. Requiring you to use a struct or an enum is not *sufficient* to ensure you'll provide value semantics, but it is *necessary* in the face of self-mutation.

The mismatch in #3 (between assuming reference semantics and requiring a class) is another, separate source of mischief: your particular value type happens to provide reference semantics even in the face of self-mutation, but it can't conform to a class-constrained protocol. This *is* a problem, but I consider it less important because you can always wrap your value type in a class to convince the compiler you know what you're doing.

In #2, the compiler is not being cautious enough; in #3, it's being too cautious. You can work around #3, but there's no fix for the recklessness in #2.

Until the compiler can verify value semantics I am not sure there is a benefit to `any<value>`. The semantic distinction is what is important. There has been discussion about strengthening the “value type == value semantics” and “reference type == reference semantics” relations but that hasn’t yet moved beyond talk.

Don't let the perfect be the enemy of the good. If the algorithm can't possibly work properly with a type that has reference semantics, then rejecting class types is a good first step, even if it doesn't reject every type with reference semantics.

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

There is a big difference between semantics that the compiler *could* but *does not yet* verify and semantics that simply cannot be verified.

And there's also a difference between research projects leading to large-scale changes to foundational language features and incremental fixes. `value` or `!class` or whatever we call it is something we could add to the language without any big redesigns or deep ponderings about the meaning of `==`. It would not be 100%, but it would filter out a fair bit of obviously incorrect code.

Incidentally, it is not possible to satisfy static property/method requirements with cases, but it probably should be:

But that is mostly tangential to this discussion.

Yes, that is very tangential. Honestly, it's kind of a tangent to a tangent.

···

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #7

You can implement reference types with value semantics and value types with reference semantics.

Immutable reference types actually *can* provide valid value semantics (at least as long as as they can provide their own implementation of `==` which I believe Dave A is arguing against).

Not in the sense I mean—that is, not if the protocol has members which require you to mutate self.

Yes, it goes without saying that an immutable reference type cannot have a mutating member.

If a reference type is immutable, you can treat it like a value type. But then it can't correctly conform to a protocol (like `RangeReplaceableCollection`) with mutating members, because it is *immutable*. It would have to take `self` as an `inout` parameter and replace `self` with a copy, but methods on classes cannot take `self` as an inout parameter. It's stuck.

It’s not just for that reason alone. An immutable type would not be able to support operations that mutate, regardless of the need to take `self` as an `inout`parameter. For example, if there were `NSImmutableArray` (`NSArray` does not guarantee immutability, it just doesn’t expose mutating operations) it would not be able to conform to `RangeReplaceableCollection` most importantly because you could not do things like `replaceSubrange`.

In other words, there are three sensible types of protocols:

1. Protocols that do not require any self-mutating members, and do not assume either value or reference semantics.
2. Protocols that require self-mutating members, and assume value semantics.
3. Protocols that require self-mutating members, and assume reference semantics.

It is also sensible to have a protocol that requires value semantics even if it does not have mutating operations. There are times when you want a guarantee that you will not observe mutations made by others.

However, what Swift actually supports is:

1. Protocols that do not require any self-mutating members, and do not assume either value or reference semantics.
2. Protocols that require self-mutating members, and can be implemented by either classes or structs/enums.
3. Protocols that require self-mutating members, and must be implemented by classes.

The mismatch in #2 (between assuming value semantics and allowing classes to conform) is one source of mischief: the compiler does nothing to help you realize that you cannot possibly correctly conform a class to the protocol. Requiring you to use a struct or an enum is not *sufficient* to ensure you'll provide value semantics, but it is *necessary* in the face of self-mutation.

The mismatch in #3 (between assuming reference semantics and requiring a class) is another, separate source of mischief: your particular value type happens to provide reference semantics even in the face of self-mutation, but it can't conform to a class-constrained protocol. This *is* a problem, but I consider it less important because you can always wrap your value type in a class to convince the compiler you know what you're doing.

In #2, the compiler is not being cautious enough; in #3, it's being too cautious. You can work around #3, but there's no fix for the recklessness in #2.

Until the compiler can verify value semantics I am not sure there is a benefit to `any<value>`. The semantic distinction is what is important. There has been discussion about strengthening the “value type == value semantics” and “reference type == reference semantics” relations but that hasn’t yet moved beyond talk.

Don't let the perfect be the enemy of the good. If the algorithm can't possibly work properly with a type that has reference semantics, then rejecting class types is a good first step, even if it doesn't reject every type with reference semantics.

Fair enough. But in that case I think we want something that does exactly that: rejects classes, rather than indicating value semantics. We need to do this in a way that doesn’t lead to a situation where we used the word `value` to mean “value type”, and later we have the capability to very value semantics and really wish `value` could mean value semantics but that would be a breaking change we aren’t willing to make.

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

There is a big difference between semantics that the compiler *could* but *does not yet* verify and semantics that simply cannot be verified.

And there's also a difference between research projects leading to large-scale changes to foundational language features and incremental fixes. `value` or `!class` or whatever we call it is something we could add to the language without any big redesigns or deep ponderings about the meaning of `==`. It would not be 100%, but it would filter out a fair bit of obviously incorrect code.

I don’t think this is a research project. IIRC the core team has already talked positively about supporting pure functions eventually, for example. There is a lot of overlap in the work to verify that a function is pure and the work involved in verifying value semantics.

Incidentally, it is not possible to satisfy static property/method requirements with cases, but it probably should be:

But that is mostly tangential to this discussion.

Yes, that is very tangential. Honestly, it's kind of a tangent to a tangent.

I don’t think it’s that far off. It’s related to Any<enum> because protocols with case requirements could only be implemented by an enum. But that’s a discussion for another day (and is probably not the best way to achieve the goal behind that request anyway).

···

On May 20, 2016, at 8:53 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies


(Dave Abrahams) #8

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.

You can implement reference types with value semantics and value types
with reference semantics. Until the compiler can verify value
semantics I am not sure there is a benefit to `any<value>`. The
semantic distinction is what is important. There has been discussion
about strengthening the “value type == value semantics” and “reference
type == reference semantics” relations but that hasn’t yet moved
beyond talk.

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

Immutable reference types actually *can* provide valid value semantics
(at least as long as as they can provide their own implementation of
`==` which I believe Dave A is arguing against).

I am not making a strong argument against that, though it might be
reasonable. I am mostly arguing in favor of a default definition of ==
for all reference types that is equivalent to ===.

···

on Fri May 20 2016, Matthew Johnson <swift-evolution@swift.org> wrote:

On May 20, 2016, at 7:40 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

There is a big difference between semantics that the compiler *could*
but *does not yet* verify and semantics that simply cannot be
verified.

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

This is a good example of why the semantics aren’t so simple.

* 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
   }

I think there was discussion at some point about introducing enum case
requirements into protocols. But that is mostly tangential to this
discussion.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave


(Adrian Zubarev) #9

Fair enough. But in that case I think we want something that does exactly that: rejects classes, rather than indicating value semantics. We need to do this in a way that doesn’t lead to a situation where we used the word `value` to mean “value type”, and later we have the capability to very value semantics and really wish `value` could mean value semantics but that would be a breaking change we aren’t willing to make.
Exactly, `any<class>` is just a constraint that indicates which type it can hold, where `any<struct>` or `any<enum>` are two constraints and (not yet existing) counterparts to `any<class>`.

The idea behind `any<struct>` (or `any<enum>`) might look like this:

func foo(struct: any<struct, SomeProtocol>)

Where it is clear that you have to provide a custom struct which conforms to `SomeProtocol`, you’re not constrained to just a single struct, you can build as many as you want it it’s your desire. :slight_smile:

Lets just imagine we already have `any<…>` and we also get `oneOf<…>` or `one<…>` which picks only one constraint at compile time and proceeds.

Here is what you could do for extendable types:

typealias AnyValue = one<any<struct>, any<enum>>

func boo(value: any<AnyValue, SomeProtocol>)

Not sure if we’ll get there or not but its a nice imagination. :slight_smile:

I’m not exactly in favor of using `any<class>` instead of AnyClass but I’m openminded. :slight_smile:

One problem to solve is the conformance to protocols:

If we’ll get `any<…>` and depricate `AnyClass` `AnyObject` we cannot do this directly:

protocol A: any<class> {}
protocol B: any<ProtocolX, ProtocolY>

We still need a typealias as a workaround:

typealias AnyClass = any<class>
typealias AnyXY = any<ProtocolX, ProtocolY>

protocol A: AnyClass {} furthermore is this protocol equivalent to protocol A: class {} ???
protocol B: AnyXY {}

···

--
Adrian Zubarev
Sent with Airmail


(Matthew Johnson) #10

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.

You can implement reference types with value semantics and value types
with reference semantics. Until the compiler can verify value
semantics I am not sure there is a benefit to `any<value>`. The
semantic distinction is what is important. There has been discussion
about strengthening the “value type == value semantics” and “reference
type == reference semantics” relations but that hasn’t yet moved
beyond talk.

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

Immutable reference types actually *can* provide valid value semantics
(at least as long as as they can provide their own implementation of
`==` which I believe Dave A is arguing against).

I am not making a strong argument against that, though it might be
reasonable. I am mostly arguing in favor of a default definition of ==
for all reference types that is equivalent to ===.

Sorry I misunderstood. To make sure I understand clearly: you’re not arguing against reference types with value semantics, just that we should allow reference semantics to be assumed unless custom equality is implemented. Is that correct?

···

On May 22, 2016, at 1:23 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Fri May 20 2016, Matthew Johnson <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 20, 2016, at 7:40 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

There is a big difference between semantics that the compiler *could*
but *does not yet* verify and semantics that simply cannot be
verified.

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

This is a good example of why the semantics aren’t so simple.

* 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
  }

I think there was discussion at some point about introducing enum case
requirements into protocols. But that is mostly tangential to this
discussion.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Austin Zheng) #11

Another thing to consider is that AnyObject currently has magic that allows any Objective-C method to be called upon it if Foundation is imported on an Apple platform. I think it may be desirable to have AnyObject become something like Any<class>, and have a differently-named construct take the place of an ersatz 'id' type for Objective-C interop.

Austin

···

On May 20, 2016, at 11:42 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Fair enough. But in that case I think we want something that does exactly that: rejects classes, rather than indicating value semantics. We need to do this in a way that doesn’t lead to a situation where we used the word `value` to mean “value type”, and later we have the capability to very value semantics and really wish `value` could mean value semantics but that would be a breaking change we aren’t willing to make.

Exactly, `any<class>` is just a constraint that indicates which type it can hold, where `any<struct>` or `any<enum>` are two constraints and (not yet existing) counterparts to `any<class>`.

The idea behind `any<struct>` (or `any<enum>`) might look like this:

func foo(struct: any<struct, SomeProtocol>)

Where it is clear that you have to provide a custom struct which conforms to `SomeProtocol`, you’re not constrained to just a single struct, you can build as many as you want it it’s your desire. :slight_smile:

Lets just imagine we already have `any<…>` and we also get `oneOf<…>` or `one<…>` which picks only one constraint at compile time and proceeds.

Here is what you could do for extendable types:

typealias AnyValue = one<any<struct>, any<enum>>

func boo(value: any<AnyValue, SomeProtocol>)

Not sure if we’ll get there or not but its a nice imagination. :slight_smile:

I’m not exactly in favor of using `any<class>` instead of AnyClass but I’m openminded. :slight_smile:

One problem to solve is the conformance to protocols:

If we’ll get `any<…>` and depricate `AnyClass` `AnyObject` we cannot do this directly:

protocol A: any<class> {}
protocol B: any<ProtocolX, ProtocolY>

We still need a typealias as a workaround:

typealias AnyClass = any<class>
typealias AnyXY = any<ProtocolX, ProtocolY>

protocol A: AnyClass {} furthermore is this protocol equivalent to protocol A: class {} ???
protocol B: AnyXY {}

--
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #12

Another thing to consider is that AnyObject currently has magic that allows any Objective-C method to be called upon it if Foundation is imported on an Apple platform. I think it may be desirable to have AnyObject become something like Any<class>, and have a differently-named construct take the place of an ersatz 'id' type for Objective-C interop.
I’m not sure if this will be the case, just because this proposal is accepted:

https://github.com/apple/swift-evolution/blob/master/proposals/0072-eliminate-implicit-bridging-conversions.md

And this might be accepted as well (which I defiantly support):

https://github.com/apple/swift-evolution/blob/master/proposals/0083-remove-bridging-from-dynamic-casts.md

···

--
Adrian Zubarev
Sent with Airmail


(Dave Abrahams) #13

I don't view an immutable class with custom equality as problematic in
principle, but if dropping that capability would allow us to simplify
the programming model, I would do so in a heartbeat. I haven't had the
chance to consider all the implications yet, but—at least until someone
can demonstrate that we really custom == for classes—we should be open
to the idea as we consider the value semantics story.

···

on Sun May 22 2016, Matthew Johnson <swift-evolution@swift.org> wrote:

On May 22, 2016, at 1:23 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:

on Fri May 20 2016, Matthew Johnson >> <swift-evolution@swift.org >> <mailto:swift-evolution@swift.org>> >> wrote:

On May 20, 2016, at 7:40 PM, Brent Royal-Gordon via >>>> swift-evolution >>>> <swift-evolution@swift.org> wrote:

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.

You can implement reference types with value semantics and value types
with reference semantics. Until the compiler can verify value
semantics I am not sure there is a benefit to `any<value>`. The
semantic distinction is what is important. There has been discussion
about strengthening the “value type == value semantics” and “reference
type == reference semantics” relations but that hasn’t yet moved
beyond talk.

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

Immutable reference types actually *can* provide valid value semantics
(at least as long as as they can provide their own implementation of
`==` which I believe Dave A is arguing against).

I am not making a strong argument against that, though it might be
reasonable. I am mostly arguing in favor of a default definition of ==
for all reference types that is equivalent to ===.

Sorry I misunderstood. To make sure I understand clearly: you’re not
arguing against reference types with value semantics, just that we
should allow reference semantics to be assumed unless custom equality
is implemented. Is that correct?

--
-Dave


(Brent Royal-Gordon) #14

I haven't had the
chance to consider all the implications yet, but—at least until someone
can demonstrate that we really custom == for classes—we should be open
to the idea as we consider the value semantics story.

I've been lurking and skimming the discussion around this so far, but I'll speak up at this point. I really do think making `==` always be an identity check for class types is not a realistic option.

What you're proposing is essentially what Objective-C does. When Swift was introduced, the ability to use operators like `==` to mean *logical* equality instead of *referential* equality was touted as a major advantage. And it *is* a major advantage for readability—`text1 == text2` (where text1 and text2 are, say, NSMutableString or NSAttributedString) is much nicer than `text1.isEqual(text2)`. We would be giving up a significant feature of the language for a vision of purity that most programmers don't (think they) care about.

Now, one thing you *could* do is allow overloading of `==` and instead take `===` for this purpose. `===` is already an identity check on reference types and unavailable on value types; for value types, it could be defined as always equivalent to `==`. This would leave `==` open to user definition on class types, while exposing your value equality operation as `===`.

Either way, though, if `Hashable` is always identity-based on class types, that will cause bridging issues. NSDictionary and Dictionary (or NSSet and Set) will no longer agree on which objects are distinct and which are not. Converting from the Swift type to the Foundation type and back again may lose elements. If we broaden `===` to all instances, `Hashable` will probably still need to be tied to `==`, not `===`.

It's unfortunate that those darned users are always getting in the way of our elegant designs. :^)

···

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #15

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.

You can implement reference types with value semantics and value types
with reference semantics. Until the compiler can verify value
semantics I am not sure there is a benefit to `any<value>`. The
semantic distinction is what is important. There has been discussion
about strengthening the “value type == value semantics” and “reference
type == reference semantics” relations but that hasn’t yet moved
beyond talk.

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

Immutable reference types actually *can* provide valid value semantics
(at least as long as as they can provide their own implementation of
`==` which I believe Dave A is arguing against).

I am not making a strong argument against that, though it might be
reasonable. I am mostly arguing in favor of a default definition of ==
for all reference types that is equivalent to ===.

Sorry I misunderstood. To make sure I understand clearly: you’re not
arguing against reference types with value semantics, just that we
should allow reference semantics to be assumed unless custom equality
is implemented. Is that correct?

I don't view an immutable class with custom equality as problematic in
principle, but if dropping that capability would allow us to simplify
the programming model, I would do so in a heartbeat. I haven't had the
chance to consider all the implications yet, but—at least until someone
can demonstrate that we really custom == for classes—we should be open
to the idea as we consider the value semantics story.

I agree that we should be open to this idea.

As we discussed previously, I would like to see some additional features around value types that would reduce or eliminate the reasons people might want to write immutable / value semantic classes introduced before we make a change like this. But if it turns out to be the right long term decision and we can’t wait that long we should go ahead with it anyway.

···

On May 22, 2016, at 3:51 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sun May 22 2016, Matthew Johnson <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 22, 2016, at 1:23 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
on Fri May 20 2016, Matthew Johnson >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> >>> wrote:

On May 20, 2016, at 7:40 PM, Brent Royal-Gordon via >>>>> swift-evolution >>>>> <swift-evolution@swift.org> wrote:

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #16

I haven't had the
chance to consider all the implications yet, but—at least until someone
can demonstrate that we really custom == for classes—we should be open
to the idea as we consider the value semantics story.

I've been lurking and skimming the discussion around this so far, but
I'll speak up at this point. I really do think making `==` always be
an identity check for class types is not a realistic option.

What you're proposing is essentially what Objective-C does. When Swift
was introduced, the ability to use operators like `==` to mean
*logical* equality instead of *referential* equality was touted as a
major advantage. And it *is* a major advantage for readability—`text1
== text2` (where text1 and text2 are, say, NSMutableString or
NSAttributedString) is much nicer than `text1.isEqual(text2)`.

Yes, but:

1. The equality operator is supposed to mean substitutability, and the
   the fact that identity is significant for mutable class types means
   `==` instances are not substitutable for one another.

2. IIUC these things should not be reference types in Swift, and pretty
   soon they won't be.

We would be giving up a significant feature of the language for a
vision of purity that most programmers don't (think they) care about.

Not for a “vision of purity;” for coherence and simplicity. If Swift
was about addressing only things programmers *think* they care about, we
wouldn't have value semantic arrays or strings.

Now, one thing you *could* do is allow overloading of `==` and instead
take `===` for this purpose. `===` is already an identity check on
reference types and unavailable on value types; for value types, it
could be defined as always equivalent to `==`. This would leave `==`
open to user definition on class types, while exposing your value
equality operation as `===`.

I think that would continue to break generic programming. There are
already a few generic components in the standard library that won't work
as expected with reference types, and these were written by people aware
of the issue! I don't think this is a practical programming model for
most people.

We'd have to tell them, “it doesn't matter that your algorithm seems to
work just fine with `==` when you tested it with `Int`s; you have to use
`===` or it will break in subtle ways when used with reference types.
And when you *do* use `===`, remember that you're only getting reference
equality, so the equality semantics you normally expect for mutable
reference types doesn't apply.” It's just not a tenable system.

Either way, though, if `Hashable` is always identity-based on class
types, that will cause bridging issues.
NSDictionary and Dictionary (or NSSet and Set) will no longer agree on
which objects are distinct and which are not. Converting from the
Swift type to the Foundation type and back again may lose elements. If
we broaden `===` to all instances, `Hashable` will probably still need
to be tied to `==`, not `===`.

If all these reference types bridge to values in Swift, I don't think we
have a problem.

It's unfortunate that those darned users are always getting in the way
of our elegant designs. :^)

Smiley aside, I don't agree with your implication that I'm prioritizing
purity over user experience. This is *all about* the user experience.

···

on Sun May 22 2016, Brent Royal-Gordon <swift-evolution@swift.org> wrote:

--
-Dave


(Adrian Zubarev) #17

I added a draft proposal here: https://github.com/DevAndArtist/swift-evolution/blob/rename_anyobject_remove_anyclass/proposals/nnnn-rename-anyobject-remove-anyclass.md

Rename AnyObject and remove current AnyClass

Proposal: SE-NNNN
Author(s): Adrian Zubarev
Status: Awaiting review
Review manager: TBD
Introduction

From the beginning AnyObject protocol and AnyClass type-alias felt wrong and confusing. This proposal aims to sort out the confusion and provide a consistency for future version of Swift.

Swift-evolution thread: [Pitch] Rename AnyObject to AnyClass and drop current AnyClass

Motivation

In Swift 3 the standard library will correspond to a particular guideline. This means that the Type suffix will be removed almost everywhere. This provides good readability and makes usage of .Type more clearer and consistent. Furthermore this change is a first step towards consistency for generalized existentials.

Short example:

-func construct(type: AnyClass) -> AnyObject?
+func construct(type: AnyClass.Type) -> AnyClass? {
    if let objectType = type as? NSObject.Type {
        return objectType.init()
    } else {
        return nil
    }
}
Proposed solution

Remove current AnyClass type-alias from the standard library and rename current AnyObject protocol to AnyClass. Then migrate existing code from AnyClass to AnyClass.Type and from AnyObject to AnyClass.

// Remove completely
-public typealias AnyClass = AnyObject.Type

// Rename to AnyClass
-@objc public protocol AnyObject {}
+@objc public protocol AnyClass {}
Impact on existing code

This change will break existing code, and will require a migrator to translate Swift 2 code into Swift 3 code.

Alternatives considered & Future consistency

Use generalized existentials with any-class requirement Any<class> instead, which won’t make it into Swift 3 in time:
AnyClass equals Any<class> or typealias AnyClass = Any<class>
AnyClass.Type equals Any<class>.Type
Add AnyValue type-alias with generalized existentials and value keyword:
AnyValue equals Any<value> or typealias AnyValue = Any<value>
AnyValue.Type equals Any<value>.Type
Or instead AnyValue add AnyStruct and AnyEnum type-aliases:
AnyStruct equals Any<struct> or typealias AnyStruct = Any<struct>
AnyEnum equals Any<enum> or typealias AnyEnum = Any<enum>
AnyStruct.Type equals Any<struct>.Type
AnyEnum.Type equals Any<enum>.Type
Example:

// Accept any type that conforms to `SomeProtocol`
func doSomething(with interface: SomeProtocol) { ... }

// Accept any class that conforms to `SomeProtocol`
// We use shorthand syntax for existentials here (SE-0095)
func doSomething(with interfaceReference: AnyClass & SomeProtocol) { ... }
func doSomething(with interfaceReference: Any<class> & SomeProtocol) { ... }

// Accept any value that conforms to `SomeProtocol`
// Missing counterpart to `AnyClass`
func doSomething(with interfaceValue: AnyValue & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<value> & SomeProtocol) { ... }

// Or more specific value types:
func doSomething(with interfaceValue: AnyStruct & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<struct> & SomeProtocol) { ... }

func doSomething(with interfaceValue: AnyEnum & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<enum> & SomeProtocol) { ... }

···

--
Adrian Zubarev
Sent with Airmail


(Patrick Smith) #18

I find this more confusing, not less. AnyClass suggests that will be any class, but it’s not, it’s any class instance. So I think it’s less accurate.

For arguments that AnyStruct and AnyEnum will come, I don’t agree with those either. AnyValue would make more sense to me. The fact that a value’s type is a struct or enum is irrelevant, just as AnyObject makes no promise about the superclass. I don’t believe there would be much or anything you could do knowing if something was a struct or enum anyway — both support properties and methods, mutations, yet cases can only be used with a concrete enum type. So AFAIK, there would no um value in having both AnyStruct and AnyEnum.

So I am happy staying with AnyObject, as it describes what the actual instance is. And if AnyValue comes, they would pair nicely together.

Patrick

···

On 9 Jun 2016, at 8:08 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

I added a draft proposal here: https://github.com/DevAndArtist/swift-evolution/blob/rename_anyobject_remove_anyclass/proposals/nnnn-rename-anyobject-remove-anyclass.md
Rename AnyObject and remove current AnyClass

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/nnnn-rename-anyobject-remove-anyclass.md>
Author(s): Adrian Zubarev <https://github.com/DevAndArtist>
Status: Awaiting review <x-msg://100/#rationale>
Review manager: TBD
Introduction

From the beginning AnyObject protocol and AnyClass type-alias felt wrong and confusing. This proposal aims to sort out the confusion and provide a consistency for future version of Swift.

Swift-evolution thread: [Pitch] Rename AnyObject to AnyClass and drop current AnyClass <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160516/018283.html>
Motivation

In Swift 3 the standard library will correspond to a particular guideline <https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md>. This means that the Type suffix will be removed almost everywhere. This provides good readability and makes usage of .Type more clearer and consistent. Furthermore this change is a first step towards consistency for generalized existentials <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>.

Short example:

-func construct(type: AnyClass) -> AnyObject?
+func construct(type: AnyClass.Type) -> AnyClass? {
    if let objectType = type as? NSObject.Type {
        return objectType.init()
    } else {
        return nil
    }
}
Proposed solution

Remove current AnyClass type-alias from the standard library and rename current AnyObject protocol to AnyClass. Then migrate existing code from AnyClass to AnyClass.Type and from AnyObject to AnyClass.

// Remove completely
-public typealias AnyClass = AnyObject.Type

// Rename to AnyClass
-@objc public protocol AnyObject {}
+@objc public protocol AnyClass {}
Impact on existing code

This change will break existing code, and will require a migrator to translate Swift 2 code into Swift 3 code.

Alternatives considered & Future consistency

Use generalized existentials with any-class requirement Any<class> instead, which won’t make it into Swift 3 in time:
AnyClass equals Any<class> or typealias AnyClass = Any<class>
AnyClass.Type equals Any<class>.Type
Add AnyValue type-alias with generalized existentials and value keyword:
AnyValue equals Any<value> or typealias AnyValue = Any<value>
AnyValue.Type equals Any<value>.Type
Or instead AnyValue add AnyStruct and AnyEnum type-aliases:
AnyStruct equals Any<struct> or typealias AnyStruct = Any<struct>
AnyEnum equals Any<enum> or typealias AnyEnum = Any<enum>
AnyStruct.Type equals Any<struct>.Type
AnyEnum.Type equals Any<enum>.Type
Example:

// Accept any type that conforms to `SomeProtocol`
func doSomething(with interface: SomeProtocol) { ... }

// Accept any class that conforms to `SomeProtocol`
// We use shorthand syntax for existentials here (SE-0095)
func doSomething(with interfaceReference: AnyClass & SomeProtocol) { ... }
func doSomething(with interfaceReference: Any<class> & SomeProtocol) { ... }

// Accept any value that conforms to `SomeProtocol`
// Missing counterpart to `AnyClass`
func doSomething(with interfaceValue: AnyValue & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<value> & SomeProtocol) { ... }

// Or more specific value types:
func doSomething(with interfaceValue: AnyStruct & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<struct> & SomeProtocol) { ... }

func doSomething(with interfaceValue: AnyEnum & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<enum> & SomeProtocol) { ... }

--
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #19

So what is the counterpart to AnyClass aka. AnyObject.Type for AnyValue? There is no and I don’t see any good name for it.

More confusion with generalized existentials:

Any<class> vs. AnyClass aka AnyObject.Type
Any<class> makes it crystal clear that you’re using an instance of a class not an instance of .Type. It should be consistent.

I’m not proposing for AnyStruct or AnyEnum here, it would be enough to get AnyValue in Swift, but I did considered both in my proposal.

Lets say we also would have something like One<A, B> which picks A or B and we have generalized struct and enum. That said we could create AnyValue like this typealias AnyValue = One<struct, enum>. Again this is not the main part of the proposal.

···

--
Adrian Zubarev
Sent with Airmail

Am 9. Juni 2016 um 13:09:28, Patrick Smith (pgwsmith@gmail.com) schrieb:

I find this more confusing, not less. AnyClass suggests that will be any class, but it’s not, it’s any class instance. So I think it’s less accurate.

For arguments that AnyStruct and AnyEnum will come, I don’t agree with those either. AnyValue would make more sense to me. The fact that a value’s type is a struct or enum is irrelevant, just as AnyObject makes no promise about the superclass. I don’t believe there would be much or anything you could do knowing if something was a struct or enum anyway — both support properties and methods, mutations, yet cases can only be used with a concrete enum type. So AFAIK, there would no um value in having both AnyStruct and AnyEnum.

So I am happy staying with AnyObject, as it describes what the actual instance is. And if AnyValue comes, they would pair nicely together.

Patrick

On 9 Jun 2016, at 8:08 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

I added a draft proposal here: https://github.com/DevAndArtist/swift-evolution/blob/rename_anyobject_remove_anyclass/proposals/nnnn-rename-anyobject-remove-anyclass.md

Rename AnyObject and remove current AnyClass

Proposal: SE-NNNN
Author(s): Adrian Zubarev
Status: Awaiting review
Review manager: TBD
Introduction

From the beginning AnyObject protocol and AnyClass type-alias felt wrong and confusing. This proposal aims to sort out the confusion and provide a consistency for future version of Swift.

Swift-evolution thread: [Pitch] Rename AnyObject to AnyClass and drop current AnyClass

Motivation

In Swift 3 the standard library will correspond to a particular guideline. This means that the Type suffix will be removed almost everywhere. This provides good readability and makes usage of .Type more clearer and consistent. Furthermore this change is a first step towards consistency for generalized existentials.

Short example:

-func construct(type: AnyClass) -> AnyObject?
+func construct(type: AnyClass.Type) -> AnyClass? {
    if let objectType = type as? NSObject.Type {
        return objectType.init()
    } else {
        return nil
    }
}
Proposed solution

Remove current AnyClass type-alias from the standard library and rename current AnyObject protocol to AnyClass. Then migrate existing code from AnyClass to AnyClass.Type and from AnyObject to AnyClass.

// Remove completely
-public typealias AnyClass = AnyObject.Type

// Rename to AnyClass
-@objc public protocol AnyObject {}
+@objc public protocol AnyClass {}
Impact on existing code

This change will break existing code, and will require a migrator to translate Swift 2 code into Swift 3 code.

Alternatives considered & Future consistency

Use generalized existentials with any-class requirement Any<class> instead, which won’t make it into Swift 3 in time:
AnyClass equals Any<class> or typealias AnyClass = Any<class>
AnyClass.Type equals Any<class>.Type
Add AnyValue type-alias with generalized existentials and value keyword:
AnyValue equals Any<value> or typealias AnyValue = Any<value>
AnyValue.Type equals Any<value>.Type
Or instead AnyValue add AnyStruct and AnyEnum type-aliases:
AnyStruct equals Any<struct> or typealias AnyStruct = Any<struct>
AnyEnum equals Any<enum> or typealias AnyEnum = Any<enum>
AnyStruct.Type equals Any<struct>.Type
AnyEnum.Type equals Any<enum>.Type
Example:

// Accept any type that conforms to `SomeProtocol`
func doSomething(with interface: SomeProtocol) { ... }

// Accept any class that conforms to `SomeProtocol`
// We use shorthand syntax for existentials here (SE-0095)
func doSomething(with interfaceReference: AnyClass & SomeProtocol) { ... }
func doSomething(with interfaceReference: Any<class> & SomeProtocol) { ... }

// Accept any value that conforms to `SomeProtocol`
// Missing counterpart to `AnyClass`
func doSomething(with interfaceValue: AnyValue & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<value> & SomeProtocol) { ... }

// Or more specific value types:
func doSomething(with interfaceValue: AnyStruct & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<struct> & SomeProtocol) { ... }

func doSomething(with interfaceValue: AnyEnum & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<enum> & SomeProtocol) { ... }

--
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Patrick Smith) #20

So what is the counterpart to AnyClass aka. AnyObject.Type for AnyValue? There is no and I don’t see any good name for it.

You could just use AnyValue.Type?

More confusion with generalized existentials:

Any<class> vs. AnyClass aka AnyObject.Type
Any<class> makes it crystal clear that you’re using an instance of a class not an instance of .Type. It should be consistent.

Any<…> would be used for any of a certain type. So Any<class> to me says ‘any of class’, not ‘any class’. Whereas AnyClass says to me literally ‘any class’.

···

On 9 Jun 2016, at 9:23 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
I’m not proposing for AnyStruct or AnyEnum here, it would be enough to get AnyValue in Swift, but I did considered both in my proposal.

Lets say we also would have something like One<A, B> which picks A or B and we have generalized struct and enum. That said we could create AnyValue like this typealias AnyValue = One<struct, enum>. Again this is not the main part of the proposal.

--
Adrian Zubarev
Sent with Airmail

Am 9. Juni 2016 um 13:09:28, Patrick Smith (pgwsmith@gmail.com <mailto:pgwsmith@gmail.com>) schrieb:

I find this more confusing, not less. AnyClass suggests that will be any class, but it’s not, it’s any class instance. So I think it’s less accurate.

For arguments that AnyStruct and AnyEnum will come, I don’t agree with those either. AnyValue would make more sense to me. The fact that a value’s type is a struct or enum is irrelevant, just as AnyObject makes no promise about the superclass. I don’t believe there would be much or anything you could do knowing if something was a struct or enum anyway — both support properties and methods, mutations, yet cases can only be used with a concrete enum type. So AFAIK, there would no um value in having both AnyStruct and AnyEnum.

So I am happy staying with AnyObject, as it describes what the actual instance is. And if AnyValue comes, they would pair nicely together.

Patrick

On 9 Jun 2016, at 8:08 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I added a draft proposal here: https://github.com/DevAndArtist/swift-evolution/blob/rename_anyobject_remove_anyclass/proposals/nnnn-rename-anyobject-remove-anyclass.md
Rename AnyObject and remove current AnyClass

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/nnnn-rename-anyobject-remove-anyclass.md>
Author(s): Adrian Zubarev <https://github.com/DevAndArtist>
Status: Awaiting review <x-msg://100/#rationale>
Review manager: TBD
Introduction

From the beginning AnyObject protocol and AnyClass type-alias felt wrong and confusing. This proposal aims to sort out the confusion and provide a consistency for future version of Swift.

Swift-evolution thread: [Pitch] Rename AnyObject to AnyClass and drop current AnyClass <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160516/018283.html>
Motivation

In Swift 3 the standard library will correspond to a particular guideline <https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md>. This means that the Type suffix will be removed almost everywhere. This provides good readability and makes usage of .Type more clearer and consistent. Furthermore this change is a first step towards consistency for generalized existentials <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>.

Short example:

-func construct(type: AnyClass) -> AnyObject?
+func construct(type: AnyClass.Type) -> AnyClass? {
    if let objectType = type as? NSObject.Type {
        return objectType.init()
    } else {
        return nil
    }
}
Proposed solution

Remove current AnyClass type-alias from the standard library and rename current AnyObject protocol to AnyClass. Then migrate existing code from AnyClass to AnyClass.Type and from AnyObject to AnyClass.

// Remove completely
-public typealias AnyClass = AnyObject.Type

// Rename to AnyClass
-@objc public protocol AnyObject {}
+@objc public protocol AnyClass {}
Impact on existing code

This change will break existing code, and will require a migrator to translate Swift 2 code into Swift 3 code.

Alternatives considered & Future consistency

Use generalized existentials with any-class requirement Any<class> instead, which won’t make it into Swift 3 in time:
AnyClass equals Any<class> or typealias AnyClass = Any<class>
AnyClass.Type equals Any<class>.Type
Add AnyValue type-alias with generalized existentials and value keyword:
AnyValue equals Any<value> or typealias AnyValue = Any<value>
AnyValue.Type equals Any<value>.Type
Or instead AnyValue add AnyStruct and AnyEnum type-aliases:
AnyStruct equals Any<struct> or typealias AnyStruct = Any<struct>
AnyEnum equals Any<enum> or typealias AnyEnum = Any<enum>
AnyStruct.Type equals Any<struct>.Type
AnyEnum.Type equals Any<enum>.Type
Example:

// Accept any type that conforms to `SomeProtocol`
func doSomething(with interface: SomeProtocol) { ... }

// Accept any class that conforms to `SomeProtocol`
// We use shorthand syntax for existentials here (SE-0095)
func doSomething(with interfaceReference: AnyClass & SomeProtocol) { ... }
func doSomething(with interfaceReference: Any<class> & SomeProtocol) { ... }

// Accept any value that conforms to `SomeProtocol`
// Missing counterpart to `AnyClass`
func doSomething(with interfaceValue: AnyValue & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<value> & SomeProtocol) { ... }

// Or more specific value types:
func doSomething(with interfaceValue: AnyStruct & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<struct> & SomeProtocol) { ... }

func doSomething(with interfaceValue: AnyEnum & SomeProtocol) { ... }
func doSomething(with interfaceValue: Any<enum> & SomeProtocol) { ... }

--
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution