swiftgenericsswift-protocols

Do not understand "Member '<func>' cannot be used on value of type 'any <type>'; consider using a generic constraint instead" error


Having a problem with a protocol & generics that I am just not able to quite get a handle on.

In the code below, marked by ERROR HERE comment, I am getting the following error:

Member 'protocolMethod' cannot be used on value of type 'any Protocol1'; consider using a generic constraint instead

I assume it is complaining mainly because of the type of the item parameter is at least in some way unresolved? And I am unfortunately not finding the suggestion helpful as I don't see how a generic constraint is going to help here (at least to my understanding of them).

Honestly I kind of feel like I might just be asking too much of Swift here.

Anybody perhaps see what the problem is or have suggestions for trying to resolve this?

Added 12/26/22 - As further background, what caused the error to appear was adding the item param to the protocolMethod method on the protocol, which pretty much shows it is the core of the issue.

protocol Protocol1
{
    associatedtype DataItem
    func protocolMethod(item : DataItem)
}

protocol Protocol2 {
    associatedtype AType1: Hashable
    //...
}

class Class1<Type1: Protocol2>: NSObject
{
    
    typealias Item = Type1.AType1
    
    var delegate : (any Protocol1)?
     
    private func method1(item: Item)
    {
        delegate?.protocolMethod(item : item)  //ERROR HERE
    }
}

(using latest Xcode)


Solution

  • You get this error because when you write:

    var delegate : (any Protocol1)?
    

    You don't give the compiler any information about what DataItem is. It can be anything, and it should not matter in your Class1 implementation.

    But when you write:

    private func method1(item: Item)
    {
        delegate?.protocolMethod(item : item)  //ERROR HERE
    }
    

    You are trying to pass an object of type Type1.AType1 as an argument of a method that expects a DataItem, and since delegate can be any Protocol1 you have no guarantee that they are the same.

    The error message actually proposes a solution:

    Member 'protocolMethod' cannot be used on value of type 'any Protocol1'; consider using a generic constraint instead

    You could add another type parameter to Class1 and add a generic constraint to tell the compiler that the AType1 and DataItem need to be equal:

    class Class1<Type1: Protocol1, Type2: Protocol2>: NSObject where Type1.DataItem == Type2.AType1
    {
        
        typealias Item = Type2.AType1
        
        var delegate : Type1?
         
        private func method1(item: Item)
        {
            delegate?.protocolMethod(item : item) 
        }
    }