Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-6039] A protocol A: class is not any AnyObject #48596

Closed
swift-ci opened this issue Oct 2, 2017 · 8 comments
Closed

[SR-6039] A protocol A: class is not any AnyObject #48596

swift-ci opened this issue Oct 2, 2017 · 8 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Oct 2, 2017

Previous ID SR-6039
Radar None
Original Reporter helge (JIRA User)
Type Bug
Status Resolved
Resolution Duplicate
Environment

Xcode 9 release, fails in both Swift 3.2 and 4.0.

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee @slavapestov
Priority Medium

md5: 682bea115f67f555845ccdf4074ae4fd

duplicates:

  • SR-55 non-@objc protocol existentials do not conform to their own protocol type

Issue Description:

I want to restrict a function to only work w/ reference types. In protocols this is expressed using `protocol A : class` and in generics as `T: AnyObject`. So I assumed this would work:

//: Playground - noun: a place where people can play

protocol AwesomeKind : class {}
class    Awesome     : AwesomeKind {}

let a   =   Awesome()
let b   =   Awesome()
var arr : [ Awesome ] = [ a, b ]

func idxIndenticalTo<T: AnyObject>(arr: [ T ], item: T) -> Int? {
  return arr.index(where: { $0 === item })
}

let i = idxIndenticalTo(arr: arr, item: b) //1

let c    :   AwesomeKind   = Awesome()
let d    :   AwesomeKind   = Awesome()
var arr2 : [ AwesomeKind ] = [ c, d ]
let k = idxIndenticalTo(arr: arr2, item: d) //1
  // error: cannot convert value of type '[AwesomeKind]' to expected argument type
  // or
  // error: cannot invoke 'idxIndenticalTo' with an argument list of type '(arr: [AwesomeKind], item: AwesomeKind)'

Why is a `protocol A: class` not an `AnyObject`? It should be exactly the same?

But OK, so lets assume `AnyObject` is something different. And indeed I can do this:

protocol AwesomeKind:class,AnyObject {}

But this still results in the same issue.

I'm pretty sure this is a bug or oversight, don't know :-)

P.S. My real code goes more like this, but the above is the easier version:

public extension Array where Element : AnyObject {
  public func indexSetForObjectsIdentical<S: Sequence>(to objects: S)
                -> IndexSet
                where S.Element : AnyObject

Which produces

// error: 'MyCoolClassProtocolType' is not convertible to 'AnyObject'
@belkadan
Copy link
Contributor

belkadan commented Oct 2, 2017

This is correct behavior. While an array of protocol values can be converted to an array of AnyObject, it does not have the same representation, much as an array of String can be converted to an array of NSString despite not being the same.

The reason for the different representation is to store how the instance conforms to the protocol, in addition to the reference itself.

(@slavapestov, what do you think we should do with this bug?)

@swift-ci
Copy link
Collaborator Author

swift-ci commented Oct 2, 2017

Comment by Helge Heß (JIRA)

To be honest I don't understand anything of what you said. Why does the array matter? Why has converting a String to NSString has any relevance here? This is not about conversion but a type being a reference type.

My question is about pure Swift. The protocol declares explicitly that the type represents an object (using `protocol A: class`). It can even explicitly declare that the protocol is an AnyObject (using `protocol A: class, AnyObject`). Yet it still isn't convertible to AnyObject. That just makes zero sense and doesn't sounds like 'correct behaviour' at all.

@slavapestov
Copy link
Member

A value of protocol type carries a payload together with a witness table. So it can be converted to a reference type via a representation change, but it is not directly usable as one. This is why you cannot bind a protocol type to a generic parameter that is class constrained.

This is more of an implementation restriction than a language design decision, but it is difficult to change now so we are probably stuck with it.

@swift-ci
Copy link
Collaborator Author

swift-ci commented Oct 2, 2017

Comment by Helge Heß (JIRA)

OK, so I suppose that means it is more for Swift 5 then. Fair enough.

@swift-ci
Copy link
Collaborator Author

Comment by Łukasz (JIRA)

But why is that marked as resolved?

@slavapestov
Copy link
Member

I resolved it because it's a duplicate of SR-55.

@mikchmie
Copy link

Fun fact - if you declare a protocol like this:

protocol Something: class {}

and cmd click the "class" word in Xcode (9.2), it will navigate to:

public typealias AnyObject

So even Xcode thinks they are the same thing.

@swift-ci
Copy link
Collaborator Author

Comment by Alejandro Ravasio (JIRA)

@slavapestov said
This is more of an implementation restriction than a language design decision, but it is difficult to change now so we are probably stuck with it.

Are we stuck with it indefinitely or is this something we can expect from Swift5 or something in the future?

We can already do this using NSObjects in Swift, but it feels more like a smelly hack than an actual solution.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

4 participants