How to modify generic struct if it also conforms to protocol

I'm wondering if anyone can suggest a nicer way to write the following code.
This is in an HTTP Client class. ResponseType is a generic Struct (defining the expected response type)

Sometimes, it also confirms to WantsHeader - in which case, I want to set the header

        do {
            let response: ResponseType = try data.decoded(using: decoder)

            if var response = response as? WantsHeaders {
                response.allHeaderFields = httpResponse.allHeaderFields
                    // swiftlint:disable:next force_cast
                completion(.success(Indexed(response as! ResponseType, index)))
                return
            }

            completion(.success(Indexed(response, index)))
            return
        } catch {
            completion(.failure(.decodingFailure))
            return
        }

I don't like that I'm returning from three places, and I'm having to use a force cast.

Is there a better way to write this?

I would like to be able to test for both required types in the if - but can't test the generic

Do you have any other usages for WantsHeaders or is just a marker protocol? If you don’t you could just add a flag “allHeadersRequired” and an optional “allHeaders” field and just set it when the flag is true.

it marks whether the response type can accept headers (and defines the method which allows the headers to be set)

I think the difficulty is because you're trying to use generic struct to implement optional feature. That's not what generics is good at.

Approach 1) Define two generic struct, one for response type supporting header, and one for not supportingg header. Both conform to response protocol. Then you can change your code like the follwing:

let response: ResponseProtocol = try data.decoded(using: decoder)

if var response = response as? ResponseWithHeader {
     ...
}

Note this approach uses runtime type casting (but no force casting), which I personally always try to avoid. I prefer to approach 2, which is simple and clear.

Approach 2) Define an enum type for the decoded return value. Then you can just do a switch to process the values in difference cases properly.


BTW, if for some reason you's like to stick to your current approach (a single generic struct), you can enhance the protocol that struct's generic type parameter conform to, to include interfaces like whether the struct supports headers, etc. Then you can add header related methods to the generic struct. The question here is what will these methods do if the struct doesn't support header. The only proper behavior is to call fatalError(). I'd suggest to avoid this approach as much as possible because it's effectively a single type with two set of APIs (or in other words, using a single type for two different types).