I'm trying to declare a function in a protocol that forces types that conform to it to return a value of that same protocol but with a specific associated type:
protocol Protocol {
typealias ValueType
var value : ValueType? {get}
func getProtocolString<A where A : Protocol, A.ValueType == String>() -> A
}
This compiles. It's when I try to create a class that conforms to it that I get the errors:
class AClass<T> : Protocol {
var value : T?
func getProtocolString<A where A : Protocol, A.ValueType == String>() -> A {
return AClass<String>()
}
}
The error is 'AClass' is not convertible to 'A'.
Am I missing something? Is this even possible?
Thank you
The problem lies with confusing a generic placeholder constrained by a protocol, with the protocol itself. Here’s a simpler example, similar to your code, to try and make it clear:
// first, define a protocol and two structs that conform to it
protocol P { }
struct S1: P { }
struct S2: P { }
// now, a function that returns an object in the form
// of a reference to protocol P
func f() -> P {
// S1 conforms to P so that’s fine
return S1()
}
// ok all well and good, this works fine:
let obj = f()
// now, to do something similar to your example code,
// declare a generic function that returns a generic
// placeholder that is _constrained_ by P
// This will NOT compile:
func g<T: P>() -> T { return S1() }
Why does this not compile?
The way generic functions work is that at compile time, when you call the function, the compiler decides what type the placeholder T
needs to be, and then writes you a function with all occurrences of T
replaced with that type.
So with the example below, T
should be replaced by S1
:
let obj1: S1 = g()
// because T needs to be S1, the generic function g above is
// rewritten by the compiler like this:
func g() -> S1 { return S1() }
This looks OK. Except, what if we wanted T
to be S2
? S2
conforms to P
so is a perfectly legitimate value for T
. But how could this work:
// require our result to be of type S2
let obj2: S2 = g()
// so T gets replaced with S2… but now we see the problem.
// you can’t return S1 from a function that has a return type of S2.
// this would result in a compilation error that S2 is not
// convertible to S1
func g() -> S2 { return S1() }
Here is the origin of the error message you are getting. Your placeholder A
can stand in for any type that conforms to Protocol
, but you are trying to return a specific type (AClass
) that conforms to that protocol. So it won’t let you do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With