In the Xcode 11.4 Release Notes under the Swift section it has this:
- A method override can no longer have a generic signature with requirements not imposed by the base method. For example, the below code produces an error. (23626260) (FB5382462)
protocol P {} class Base { func foo<T>(arg: T) {} } class Derived: Base { // generates an error because of the added requirement override func foo<T: P>(arg: T) {} }
I'm confused why this change was made. It has completely broken a core part of our app which is based on this framework: GitHub - theappbusiness/TABResourceLoader: Framework for loading resources from a network service
For making network requests we have the following concepts:
- Model : Strongly typed object in your codebase, may or may not be mapped 121 to the server model
- Resource : Defines through protocol conformance where and how to fetch a Model . For example a resource could define the URL of where a JSON file is and how to parse into strongly types model.
- Service : A type that knows how to retrieve a specific kind of Resource
So we have a class NetworkDataResourceService
that can fetch Resources that conform to NetworkResourceType
and DataResourceType
:
open class NetworkDataResourceService {
open func fetch<Resource: NetworkResourceType & DataResourceType>(resource: Resource, completion: @escaping (NetworkResponse<Resource.Model>) -> Void) -> Cancellable? { ... }
}
We then have a subclass that restricts the Resource further to having to conform to ServiceableResource
:
open class ResourceService: NetworkDataResourceService {
open override func fetch<Resource: DataResourceType & NetworkResourceType & ServiceableResource>(resource: Resource, completion: @escaping (NetworkResponse<Resource.Model>) -> Void) -> Cancellable? { super.fetch(...) }
}
There are then 3 more subclasses in the same fashion, further restricting what resources can be fetched. This means that it is a compile time error to fetch a Resource from a service that doesn't support fetching it.
I can't understand why the change in Swift 5.2 was made. It seems to violate/break the Liskov Substitution Principle as ResourceType & NetworkResourceType & ServiceableResource
is effectively a subtype of ResourceType & NetworkResourceType
. The super class doesn't need to know that the Resource is also a ServiceableResource when calling super.fetch.
Is there any more information on why this change was made? (And if possible any workarounds) I've tried searching for the reference numbers in the Release notes but can't find anything.