I've written some code that I think ought to work in Swift 2 (Xcode 7b4), but it's not compiling. I'm hoping to get some thoughts on whether what I'm trying to do should be valid.
Consider this example Array
extension:
extension Array where Element: AnyObject {
mutating func appendUniqueInstance(e: Element) {
for element in self {
if (element === e) {
return
}
}
self.append(e)
}
}
First, what do I mean by an Array whose elements are AnyObject
? Basically I'm saying the array should contain a heterogeneous group of non-value-type objects that can be compared for instance equality (===
).
The example function appendUniqueInstance()
only inserts an element into an array if it isn't already in the array. This is similar to a Set
insert()
operation but obviously provides ordering and (more importantly) does not impose Set
's homogeneous-type requirement (via Equatable
's use of Self
).
If I now define a protocol P
and a class C
that implements P
:
protocol P : AnyObject {}
class C : P {}
and instantiate a C
:
let c = C()
Then these very obvious things are true:
let cIsAnyObject = c as AnyObject // ok
let cIsP = c as P // ok
And I can now do the following:
var a1 = [AnyObject]() // []
a1.appendUniqueInstance(c) // [c]
a1.appendUniqueInstance(c) // [c]
So far, so good, but now for the problem case:
var a2 = [P]()
a2.append(c) // ok, -> [c]
// Compiler error: Cannot invoke 'appendUniqueInstance' with an argument list of type '(C)'
a2.appendUniqueInstance(c)
Here, a2
is typed as an array of P
, so it should be a perfectly valid thing to do to append
an instance of P
, and indeed the line a2.append(c)
works as we'd expect.
Calling the Array
extension function appendUniqueInstance()
however generates a compiler error.
As far as I can tell, the compiler seems to be getting confused about what can be passed to appendUniqueInstance()
and not realizing (or allowing for some reason) that C
(via P
) is an AnyObject
.
Incidentally, if I declare P
instead as:
@objc protocol P : AnyObject {}
then everything compiles just fine, but I also then have to make sure everything in protocol P
conforms to @objc
, which is not what I want.
So, after all of this, my question is: does this seem like something that should work? I hope it isn't just a case of getting some declaration syntax wrong, but I guess I'll be glad if it is.
It appears the error reported by the compiler at the time I wrote the original question was simply misleading, and the functionality I was trying to obtain wasn't (and still isn't) supported by Swift.
With Xcode 8.2.1 and Swift 3 a more accurate error is reported:
// error: using 'P' as a concrete type conforming
// to protocol 'AnyObject' is not supported
a2.appendUniqueInstance(c)