Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: How can I make a function with a Subclass return type conform to a protocol, where a Superclass is defined as a return type?

I have a protocol, where a function is defined, the return type of a function is a SuperclassType.

In a class which conforms to the protocol I'm trying to define this function, but with a SubclassType return type.

Compiler tells me, that this class does not conform to the protocol, because obviously SubclassType != SuperclassType

protocol SomeProtocol {
  func someFunction(someParameter:SomeType) -> SuperclassType?
}

class SomeClass : SomeProtocol {
  func someFunction(someParameter:SomeType) -> SubclassType? {
    ...
  }
}

class SubclassType : SuperclassType { }

Common sense tells me, though, that SubclassType should be a suitable substitute for a SuperclassType in this matter.

What am I doing wrong?

Thanks.

like image 673
nikans Avatar asked Jan 29 '16 22:01

nikans


People also ask

Can a struct conform to a protocol Swift?

In Swift, protocols contain multiple abstract members. Classes, structs and enums can conform to multiple protocols and the conformance relationship can be established retroactively.

How do you declare a protocol in Swift?

Custom types state that they adopt a particular protocol by placing the protocol's name after the type's name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here.

Is it possible to prevent the adoption of a protocol by a struct?

The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. But there would be a time when you want to restrict protocols to be adopted by a specific class. In Swift 5, you can do just that.

How many protocols can a Swift class adopt?

Since classes, structures and, enums can conform to more than one protocol, they can take the default implementation of multiple protocols.


1 Answers

Before you go much further, I'd recommend some background reading on covariance vs contravariance and the Liskov substitution principle.

  • Return types for methods overridden when subclassing are covariant: the subclass override of a method can return a subtype of the superclass method's return type.

  • Generic type parameters are invariant: a specialization can neither narrow nor expand the type requirements.

The relationship between a protocol and a concrete type that adopts it is more like generics than like subclassing, so return types declared in protocols are invariant, too. (It's hard to say exactly why on first read. Possibly something about existential vs constraint-only protocols?)

You can allow covariance in a protocol by specifying associated type requirements, though:

protocol SomeProtocol {
    associatedtype ReturnType: SuperclassType
    func someFunction(someParameter: SomeType) -> ReturnType
}

class SomeClass : SomeProtocol {
    func someFunction(someParameter: SomeType) -> SubclassType { /*...*/ }
}

Now, it's clear that the return type of someFunction in a type adopting SomeProtocol must be either SuperclassType or a subtype thereof.

like image 89
rickster Avatar answered Sep 25 '22 16:09

rickster