Swift protocol generic as function return type

Swift 5.1 supports returning associated types using Opaque type. Using opaque type, your code builds successfully. Ref

protocol P {
    associatedtype T
    func get() -> T?
    func set(v: T)
}

class C<T>: P {
    private var v: T?

    func get() -> T? {
        return v
    }
    func set(v: T) {
        self.v = v
    }
}

class Factory {
    func createC<T>() -> some P {
        return C<T>()
}

The problem is you cannot use the syntax P<T>. P is a protocol, meaning it can't be treated as a generic type (Cannot specialize non-generic type 'P'), even though it may have a given associatedtype.

In fact, because it has an associatedtype, you now can't even use the protocol type itself directly – you can only use it as a generic constraint.

One solution to your problem is to simply change your function signature to createC<T>() -> C<T>, as that's exactly what it returns.

class Factory {
    func createC<T>() -> C<T> {
        return C<T>()
    }
}

I'm not entirely sure what you would gain from having the return type be a protocol here. Presumably your example is just a simplification of your actual code and you want to be able to return an arbitrary instance that conforms to P. In that case, you could use type erasure:

class AnyP<T> : P {

    private let _get : () -> T?
    private let _set : (T) -> ()

    init<U:P where U.T == T>(_ base:U) {
        _get = base.get
        _set = base.set
    }

    func get() -> T? {return _get()}
    func set(v: T) {_set(v)}
}

class Factory {
    func createC<T>() -> AnyP<T> {
        return AnyP(C<T>())
    }
}

Tags:

Generics

Swift