Using as a Concrete Type Conforming to Protocol Anyobject Is Not Supported

Using as a concrete type conforming to protocol AnyObject is not supported

I had the same idea to create weak container with generics.

As result I created wrapper for NSHashTable and did some workaround for your compiler error.

class WeakSet<ObjectType>: SequenceType {

var count: Int {
return weakStorage.count
}

private let weakStorage = NSHashTable.weakObjectsHashTable()

func addObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.addObject(object as? AnyObject)
}

func removeObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.removeObject(object as? AnyObject)
}

func removeAllObjects() {
weakStorage.removeAllObjects()
}

func containsObject(object: ObjectType) -> Bool {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
return weakStorage.containsObject(object as? AnyObject)
}

func generate() -> AnyGenerator<ObjectType> {
let enumerator = weakStorage.objectEnumerator()
return anyGenerator {
return enumerator.nextObject() as! ObjectType?
}
}
}

Usage:

protocol MyDelegate : AnyObject {
func doWork()
}

class MyClass: AnyObject, MyDelegate {
fun doWork() {
// Do delegated work.
}
}

var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())

for delegate in delegates {
delegate.doWork()
}

It's not the best solution, because WeakSet can be initialized with any type, and if this type doesn't conform to AnyObject protocol then app will crash. But I don't see any better solution right now.

Using 'Protocol' as a concrete type conforming to protocol 'Protocol' is not supported

Fix is replacing Element: Animal with Element == Animal.

Using some protocol as a concrete type conforming to another protocol is not supported

The underlying reason for the limitation is that Swift doesn't have first-class metatypes. The simplest example is that this doesn't work:

func isEmpty(xs: Array) -> Bool {
return xs.count == 0
}

In theory, this code could work, and if it did there would be a lot of other types I could make (like Functor and Monad, which really can't be expressed in Swift today). But you can't. You need to help Swift nail this down to a concrete type. Often we do that with generics:

func isEmpty<T>(xs: [T]) -> Bool {
return xs.count == 0
}

Notice that T is totally redundant here. There is no reason I should have to express it; it's never used. But Swift requires it so it can turn the abstract Array into the concrete [T]. The same is true in your case.

This is a concrete type (well, it's an abstract type that will be turned into a concrete type any time it's instantiated and P is filled in):

class ImplementProtocolA<P : ProtocolA>

This is a fully abstract type that Swift doesn't have any rule to turn into a concrete type:

class ImplementProtocolB : ImplementProtocolA<ProtocolB>

You need to make it concrete. This will compile:

class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}

And also:

class UserDemoPresenter<T: GetUserView> : Presenter {
typealias V = T
}

Just because you're likely to run into the issue later: your life will go much easier if you'll make these structs or final classes. Mixing protocols, generics, and class polymorphism is full of very sharp edges. Sometimes you're lucky and it just won't compile. Sometimes it will call things you don't expect.

You may be interested in A Little Respect for AnySequence which details some related issues.


private var presenter : UserDemoPresenter<GetUserView>

This is still an abstract type. You mean:

final class Something<T: GetUserView> {
private var presenter: UserDemoPresenter<T>
}

If that creates a problem, you'll need to create a box. See Protocol doesn't conform to itself? for discussion of how you type-erase so that you can hold abstract types. But you need to work in concrete types. You can't ultimately specialize on a protocol. You must eventually specialize on something concrete in the majority of cases.

Passing object conforming to AnyObject protocol into generic requiring AnyObject

Protocols do not conform to themselves (or to any protocol). Only concrete types can conform to a protocol.

If the only thing you need to know about this type is that it is a class (AnyObject), then you don't want a generic here, you just want to pass the protocol type itself (technically the "existential").

class Wrapper {
let value: AnyObject
init(_ value: AnyObject) {
self.value = value
}
}

If you need a generic here for some other reason, then the generic must be over a concrete type, not a protocol.

Is there information somewhere on Swift protocol associatedtype using `=` versus `:`?

The = and the : are two independent parts of an associated type declaration, rather than being mutually exclusive. This is the full syntax of protocol associated type declaration:

attributes(opt) 
access-level-modifier(opt)
'associatedtype'
typealias-name
type-inheritance-clause(opt)
typealias-assignment(opt)
generic-where-clause(opt)

The : TypeName part is the type-inheritance-clause, and the = TypeName is the typealias-assignment.

: TypeName constrains what type the associated type can be, namely that it must inherit/conform to TypeName. This is why : SomeManagerDelegate didn't work in your case. You are saying that SomeManager.DelegateType must be some kind of SomeManagerDelegate, but for Manager, this is not true - Manager.delegate is of type ManagerDelegate, which is a totally unrelated protocol. Even if it were SomeManagerDelegate, it wouldn't work either because protocols don't conform to themselves.

= TypeName sets a default type for the associated type. If the compiler cannot infer what the type the associated type for a conformance should be and you didn't say it explicitly it either, it will use that type instead. But in your case, this fact didn't really matter. What actually caused your code to work, wasn't the addition of = SomeManagerDelegate, but the removal of the constraint : SomeManagerDelegate. You are no longer constraining what type the associated type should be (it can be anything!), so for Manager, the associated type can now be inferred to be ManagerDelegate. Note that you don't have to explicitly say:

typealias DelegateType = ManagerDelegate

In fact, you can totally remove = SomeManagerDelegate and just say:

associatedtype DelegateType

so it is far from the truth that the = is "the only thing keeping it together".

This = TypeName syntax doesn't seem very well documented. Here's a related Swift forums post.



Related Topics



Leave a reply



Submit