I'm not entirely sure how to describe what I'm asking without just giving an example. The issue I'm having is motivated by using the CoreImage framework from Apple, which vends different subclasses of CIFilters, but the return types of these vending methods are specified as
CIFIlter & SomeCIFilterProtocol
For example, the photoEffectFade()
method has this signature:
open class func photoEffectFade() -> any CIFilter & CIPhotoEffect
(where CIFilter
is a class and CIPhotoEffect
is a protocol)
There are many protocols which have nearly identical definitions, but the important thing is that they all have the exact same declaration of var inputImage: CIImage? { get set }
public protocol CIPhotoEffect : CIFilterProtocol {
var inputImage: CIImage? { get set }
//...
}
public protocol CIThermal : CIFilterProtocol {
var inputImage: CIImage? { get set }
//...
}
public protocol CIComicEffect : CIFilterProtocol {
var inputImage: CIImage? { get set }
//...
}
In order to simplify the question, here is a similar example of what I am trying to accomplish:
/*
* Let's say AAA, BBB, and CCC are vended from some package.
* They all have identical `var foo: Int { get }` members
*/
protocol AAA {
var foo: Int { get }
// ...
}
protocol BBB {
var foo: Int { get }
// ...
}
protocol CCC {
var foo: Int { get }
// ...
}
/*
* Here, FooHaving is a protocol I want to implement
* which would 'unify' all of these similar above protocols
*/
protocol FooHaving {
var foo: Int { get }
}
/*
* Here I have some object that can deal with anything that has
* a `foo: Int` member
*/
struct FooPrinter<T: FooHaving> {
let fooProvider: T
func printFoo() {
print(fooProvider.foo)
}
}
/*
* Attempting to add protocol conformance to a protocol doesn't work
*/
extension AAA: FooHaving {} // error: Extension of protocol 'AAA' cannot have an inheritance clause
extension BBB: FooHaving {} // error: Extension of protocol 'BBB' cannot have an inheritance clause
extension CCC: FooHaving {} // error: Extension of protocol 'CCC' cannot have an inheritance clause
struct aaa: AAA {
var foo: Int
}
/*
* I would love to be able to do this, somehow,
* but of course it fails because AAA does not conform to FooHaving
*/
let f = FooPrinter(fooProvider: aaa()) // error: Generic struct 'FooPrinter' requires that 'aaa' conform to 'FooHaving'
/*
* My current 'workaround', which feels less than ideal,
* is to have a type erased object that can take in any
* of these separate (but similar) protocols.
*/
struct AnyFooProvider: FooHaving {
private let _provider: () -> Int
var foo: Int {
_provider()
}
init(_ x: any FooHaving) {
_provider = {
return x.foo
}
}
init(_ x: any AAA) {
_provider = {
return x.foo
}
}
init(_ x: any BBB) {
_provider = {
return x.foo
}
}
init(_ x: any CCC) {
_provider = {
return x.foo
}
}
}
Is there some way to elegantly tie these kinds of separate but similar protocols together? The type erasure workaround works, but it feels unwieldy and hacky.
It feels like this should be possible, but I am coming up short. Any thoughts are appreciated. Thanks!