jonny
(Jonny)
1
Hi
I'm trying to get the generic parameter clause type, and I'm not sure if/how the best way to go about it.
struct SomeGenericModel<T: MyProtocol> {
var a: [T]
}
I have a generic function that I pass the GenericModel to, so the type is SomeGenericModel<SomeDifferentType>. Is there a way to obtain the type of the clause is SomeDifferentType?
Lantua
2
What does the function signature look like?
If it's a generic function, you can use the function's generic parameter:
func foo<T>(_: SomeGenericModel<T>) {
// Use T.self
}
jonny
(Jonny)
3
Apologies for the late reply
I'm converting all responses from this API that are arrays to this generic struct
struct ArrayStruct<T:MyCodableProtocol> : MyArrayProtocol {
var data: [T]
}
so I have a generic function which sends requests and returns the decoded generic object
func send<T: MyCodableProtocol>(...) -> EventLoopFuture<T> {
let model = try Self.decodeRelevantType(T: T.self, response: response, decoder: self.decoder)
}
decodeRelevantType signature is this
func decodeRelevantType<T: MyCodableProtocol >(T: T.Type, response: Data, decoder: JSONDecoder) throws -> T {
switch(T) {
case is MyArrayProtocol.Type:
let x = try decode(response: response, decoder: decoder, as: T.self)
return ArrayStruct(data: x) as! T
}
So at the point where my case hits any array response type. The type is ArrayStruct<T>. Where I call as: T.self, is there anyway to get the type of the data inside the ArrayStruct. I'm assuming Type Erasure at this point, but I also want to make sure I'm not over complicating something.
I did have the case use the explicit ArrayStruct.Type but it wanted the generic clause, which looking at this post, it doesn't seem you can do [Pitch] Improving unspecified generic usability
xwu
(Xiaodi Wu)
4
I haven't worked through what you're doing here, but for a start, you've named at least four different things T, and many are shadowing each other, so I would start with naming them something more descriptive, or at least use different letters of the alphabet. That will help you figure out what you need to do.
Lantua
5
Is there anything on MyArrayProtocol that refers to T, like associated types? If not, I don't think there's any safe way to extract T. The T doesn't even know if it is an ArrayStruct<T>.
Also, what are you doing inside decodeRelevantType? You're decoding a T, create ArrayStruct<T> from it, then force it to be T. There's something fishy going on there.
From that alone, I suspect that you don't actually need all the type gymnastics you queried in the beginning.
1 Like
jonny
(Jonny)
6
Hi @Lantua No there isn't anything on the array protocol. I used that simply so I could use it in the case is MyArrayProtocol.Type because the compiler wouldn't let me use a partial generic of case is ArrayStruct.Type as it said ArrayStruct requires argument in in <...>.
Inside decodeRelevantType not much really. Just this return try decoder.decode(T.self, from: response). Which I know won't work as it will just try to decode the array of results into ArrayStruct<TypeOfArray> when really I just want to decode the response into [TypeOfArray]. So that's really my main question, is there a way to get that generic parameter clause. Almost like T.Type.Type kind of thing?
I do agree, I'm doing lots of gymnastics (my head hurts) here and have probably over complicated this and maybe gone down the rabbit hole too far. There's probably a simpler way
jonny
(Jonny)
7
Hi @Lantua No there isn't anything on the array protocol. I used that simply so I could use it in the case is MyArrayProtocol.Type because the compiler wouldn't let me use a partial generic of case is ArrayStruct.Type as it said ArrayStruct requires argument in in <...>.
Inside decodeRelevantType not much really. Just this return try decoder.decode(T.self, from: response). Which I know won't work as it will just try to decode the array of results into ArrayStruct<TypeOfArray> when really I just want to decode the response into [TypeOfArray]. So that's really my main question, is there a way to get that generic parameter clause. Almost like T.Type.Type kind of thing?
I do agree, I'm doing lots of gymnastics (my head hurts) here and have probably over complicated this and maybe gone down the rabbit hole too far. There's probably a simpler way.
Edit
I think I fixed this in a simpler fashion.
// 1. Return an array of objects instead of wrapping them in `ArrayStruct`
// 2. Add conformance to Array
extension Array: MyCodableProtocol where Element: MyCodableProtocol {}
So now I can adjust the API return routes to return EventLoopFuture<[SomeArray]> and just use the standard decoder usage return try decoder.decode(TM.self, from: response). So it handles both Array and non array types with no switches etc. Seems to work ok, all my tests are working 
Thanks for helping
Lantua
8
There's one more thing I totally forgot to ask. Are you trying to create a codable experience of sorts? I noticed the name MyCodableProtocol. If so, is there any reason not to use standard Codable?
If you switch to standard Codable, you'll immediately get its benefits, like encode/decode synthesis, third party library supports, etc. It is pretty versatile, only requiring the (nested) container to be unkeyed, stringly keyed, or intly keyed. I don't see any immediate obstacle in creating your own ResponseEncoder and ResponseDecoder.
1 Like
jonny
(Jonny)
9
MyCodableProtocol just conforms to Codable anyway. Thank you very much for your help 
Lantua
10
If it's not adding any requirement, I'd still suggest a plain Codable. You can already add default implementations right into Codable.
If there are collisions (you want to change encode behaviour), my personal suggestion is to use a wrapper type instead, and sprinkle it with property wrapper.
Using an empty protocol could only add to confusion.