2

I have faced an issue and I think rather than trying to explain, showing it will be more effective.

I have this code and when I run it prints out this

struct One: Codable {}
struct Two: Codable {}

func test<T: Codable>(ofType: T.Type) {
    print(ofType)
}

var array = Array<Codable.Type>()

array.append(One.self)
array.append(Two.self)

array.forEach { (type) in
    print(type)
} // Outs: One\nTwo

test(ofType: One.self) // out: One
test(ofType: Two.self) // out: Two

However when I try to say;

array.forEach { (type) in
    test(ofType: type)
}

it throws

Cannot convert value of type 'Codable.Type' (aka '(Decodable & Encodable).Type') to expected argument type 'T.Type'

and adding test(ofType: type as! T.Type) throws those for the forEach and test itself accordingly

Type of expression is ambiguous without more context
Cannot find type 'T' in scope

I am trying to implement this because of token refresh. When the token is refreshing I cache the requests with related type which response will be parsed into.

private static var cachedRequests: [(Endpoint, Decodable.Type)]
class func makeRequest<T: Decodable>(to endpoint: Endpoint, decodeAsWrapped type: T.Type, completion: @escaping (Result<T, Error>) -> Void)

Any suggestions?

EDIT

I want to add another weird thing as follows:

func test<T: Codable>(ofType: T.Type) {
    array.append(ofType)
}

Above code is working just fine. I can append ofType to an array however can't use any item from that exact array as an input for ofType. Extremely unexpected thing for me.

Faruk
  • 2,269
  • 31
  • 42
  • 1
    All elements of your collection should be the same generic Codable type. If you expect to be able to add different types in the same collection you are going the wrong way. Thats not what generics are meant for. – Leo Dabus Apr 25 '21 at 23:36
  • tried, still does not work. I think it would not be possible to append in the first place. – Faruk Apr 25 '21 at 23:39
  • The array itself is not generic. It just holds types that conforms to `Codable`. – Faruk Apr 25 '21 at 23:41
  • What do you need? Just a generic fetch method? – Leo Dabus Apr 25 '21 at 23:42
  • I have the generic fetch method. What I need is a way to cache each `Endpoint` with related `Codable` type that response will be decoded into. I will populate the array while access token is being refreshed, afterwards I will execute the requests I have cached using my generic fetch method. – Faruk Apr 25 '21 at 23:46
  • 1
    Just keep the response as Data – Leo Dabus Apr 25 '21 at 23:50
  • There is no response at the time because the request have not been sent yet. – Faruk Apr 25 '21 at 23:52
  • 1
    no need to use a generic type for your test method `func test(ofType: Codable.Type) { print(ofType) }` – Leo Dabus Apr 25 '21 at 23:58
  • 1
    `[Codable]` is not a sensible type. You can't talk about "unknown types that can be decoded from Data." That's highly ambiguous. Arbitrary data could be decoded to almost anything given the right rules. But I think what you're really trying to build is `[Encodable]`, which is a sensible type. Swift just doesn't currently support it. If you'll explain the problem you're trying to solve, then we can probably help. The messy type-eraser `AnyEncodable` is easy to build. It's just Swift shouldn't require it, but does. (There's a current discussion on the forums to improve this.) – Rob Napier Apr 26 '21 at 02:54
  • You are once again really really helpful. The type actually is `Decodable` in my case, but it does not matter whether `Decodable` or `Encodable`, i think. I don't know if you remember me or not but I have some other thread on this site where we had this kind of discussions and they always end with what you said again, swift just does not support it :) I hope someday it will. I have explained the problem couple comments above however i think i already found a solution on this thread https://stackoverflow.com/a/56912806/1404324 – Faruk Apr 26 '21 at 03:05
  • If not I will write here again @RobNapier I deeply thank you. – Faruk Apr 26 '21 at 03:06

1 Answers1

1

Is this what you wanted ?

struct One: Codable {}
struct Two: Codable {}

func test(ofType: Codable.Type) {
    print(ofType)
}

var array = Array<Codable.Type>()

array.append(One.self)
array.append(Two.self)

array.forEach { (type) in
    print(type)
} // Outs: One\nTwo

test(ofType: One.self) // out: One
test(ofType: Two.self) // out: Two

array.forEach { (type) in
    test(ofType: type)
} // Outs: One\nTwo
AnderCover
  • 2,488
  • 3
  • 23
  • 42
  • So just making `test` method ungeneric do the magic. As `makeRequest` has an completion depends on the generic type, I dont think this would work directly. I have solved the issue by not caching the request object and target decode type but caching the code block itself. However as this solves the example I have given, I think I should accept this answer. Thank you @AnderCover – Faruk Apr 30 '21 at 19:42
  • I'm not sure what you mean by "caching the code block itself" if caching is the issue, in my experience it is simpler to cache `Data` and let the code that query a particular cache item worry about decoding errors – AnderCover Apr 30 '21 at 19:54
  • Yeah but the case is particularly caching request while the token is being refreshed. I have written code such that it does not wait for any `401` to come as a response. So in my case right now, there is no `Data` actually. But yeah, caching requests due to some kind of decoding failure I would do the way you suggested – Faruk Apr 30 '21 at 20:00