Cannot convert swift generic subclass to generic superclass - swift

I want to write better and cleaner code using parametrized classes in Swift but I'm getting a strange build error:
Cannot convert value of type 'CustomAdapter' to expected argument type 'TableTestParametrizedAdapter<ETableViewCell>'
What I actually want is to be able to create a base adapter class with one method (overridden in adapter subclasses) used to bind cell subclasses with the corresponding data model and get rid of casting every time.
I'll post the code below, in order to understand better what I mean.
class TestParametrizedAdapter<C>: NSObject {
func doSmth(cell: C) {
}
}
class TableTestParametrizedAdapter<C>: TestParametrizedAdapter<C> where C:ETableViewCell {
}
class PeopleTableViewCell: ETableViewCell {
}
class CustomAdapter: TableTestParametrizedAdapter<PeopleTableViewCell> {
override func doSmth(cell: PeopleTableViewCell) {
}
}
class TestBaseController: UIViewController {
var adapter: TableTestParametrizedAdapter<ETableViewCell>?
override func viewDidLoad() {
super.viewDidLoad()
setAdapter(adapter: CustomAdapter()) // this is the line with build error
}
func setAdapter(adapter: TableTestParametrizedAdapter<ETableViewCell>) {
self.adapter = adapter
}
}
I have read on some other posts about this and there was pointed out that GenericClass<B> and GenericClass<A> are completely unrelated even if B is a subclass of A, hence you cannot cast one to the other. (https://stackoverflow.com/a/50859053/10115072)
Anywat, are there any solutions for this? How can we use the power of parametrization of Swift in this case? I use Swift 4.
Thanks in advance.

Even if Swift would support variance in custom generics your code would be wrong, since you try to use object that can only handle PeopleTableViewCell instances in place of object that can handle any ETableViewCell. If that is indeed what you want and you don't mind some run-time checks you can do something similar with little type erasure:
class TestAnyAdapter: NSObject {
func doSmth(cell: Any) {}
}
class TableTestParametrizedAdapter<C>: TestAnyAdapter where C:ETableViewCell {
override func doSmth(cell: Any) {
guard let cell = cell as? C else {
return
}
self.doSmth(cell: cell)
}
func doSmth(cell: C) {}
}
the rest of the code will be the same as you already have, only without compile-time error.

I agree with Konstantin about the fundamental problem here. This code is simply incorrect, and Swift is telling you so. CustomAdapter.doSmth cannot accept any arbitrary ETableViewCell, but adapter claims it must.
There are many solutions, depending on the actual problem you're trying to solve. You indicated you want to write "better and cleaner code." That suggests you have existing code where you're finding excessive duplication or casting. So what you want to do is look at that code, and see what code is being duplicated, and then we can help you design generic solutions to avoid that duplication. There is no universal answer to this question; abstraction choices you make in one direction will make other directions less flexible. Abstraction is choices; they need to be made in context.
As a rule in Swift, you should avoid relying on subclassing. There is some that is required, because of bridging to ObjC, but Swift-focused code should avoid subclasses. In your particular example, the interesting class has just one function. If that's really true, then implementing it is easy. Use one function:
func customAdapter(cell: PeopleTableViewCell) {}
class TestBaseController: UIViewController {
let adapter: (PeopleTableViewCell) -> Void = customAdapter
}
"But my real problem is more complex than that!" Ok. Then we have to talk about your real problem. Abstracting these things down to their simplest forms rightly should lead to the simplest solutions. If things are actually a bit more complex, you could use a struct and a protocol.
protocol Adapter {
associatedtype Cell: UITableViewCell
func doSmth(cell: Cell)
}
struct CustomAdapter<Cell: ETableViewCell>: Adapter {
func doSmth(cell: Cell) {}
}
class TestBaseController: UIViewController {
let adapter: CustomAdapter<PeopleTableViewCell> = CustomAdapter()
}
I'm glossing over what may be your question, which is how to make a function that only accepts PeopleTableViewCell be used where a function that accepts any ETableViewCell is required. That's impossible. It's not a limitation in Swift; it's just type-wise impossible. The best you could do is add "do nothing" or "crash" as Konstantin explains.
If you can nail down a little more what particular problem in your existing code you're trying to fix, we can probably help you design better solutions. Adding generics does not make your code "better or cleaner" by themselves (and most of the best solutions barely need generics at all in my experience).

Let's try to get some facts straight.
Let's say we have generic class C<T>.
And let's also say we have classes D and D2, where D2 is the subclass of T.
Then C<D2> is not a subclass of C<D>. They are just separate types. (We say there is not covariance.)
Let's say our generic class C<T> has a subclass C2<T>.
Then C2<D> is a subclass of C<D>, and C2<D2> is a subclass of C<D2>.
So as long as the parameterized types are the same, there's polymorphism. But there's no covariance if the parameterized types are different, even if parameterized types are class and subclass.
(Swift Optional and Swift collections get a special covariance dispensation here, but that's baked into the language; you can't the same dispensation.)

Related

Why does the protocol default value passed to the function not change, even though the function does when subclassing?

I have a protocol, to which I have assigned some default values:
protocol HigherProtocol {
var level: Int { get }
func doSomething()
}
extension HigherProtocol {
var level: Int { 10 }
func doSomething() {
print("Higher level is \(level)")
}
}
Then I have another protocol which conforms to the higher level protocol, but has different default values and implementation of functions:
protocol LowerProtocol: HigherProtocol {}
extension LowerProtocol {
var level: Int { 1 }
func doSomething() {
print("Lower level is \(level)")
}
}
I then create a class that conforms to the HigherProtocol, and then a subclass that conforms to the lower level protocol:
class HigherClass: HigherProtocol {}
class LowerClass: HigherClass, LowerProtocol {}
When I instantiate this lower class, however, it displays some odd behaviour:
let lowerClass = LowerClass()
lowerClass.level // is 1
lowerClass.doSomething() // Prints "Lower level is 10" to the console.
The default property is correct, but the default implementation of the function seems to be a hybrid of the two.
I'm wondering what's happening here?
You appear to be trying to use protocols to create multiple-inheritance. They're not designed for that, and even if you get this working, you're going to get bitten several times. Protocols are not a replacement for inheritance, multiple or otherwise. (As a rule, Swift favors composition rather than inheritance in any form.)
The problem here is that HigherClass conforms to HigherProtocol and so now has implementations for level and doSomething. LowerClass inherits from that, and wants to override those implementations. But the overrides are in a protocol extension, which is undefined behavior. See Extensions from The Swift Programming Language:
Extensions can add new functionality to a type, but they cannot override existing functionality.
Undefined behavior doesn't mean "it doesn't override." It means "anything could happen" including this weird case where it sometimes is overridden and sometimes isn't.
(As a side note, the situation is similar in Objective-C. Implementing a method in two different categories makes it undefined which one is called, and there's no warning or error to let you when this happens. Swift's optimizations can make the behavior even more surprising.)
I wish the compiler could detect these kinds of mistakes and raise an error, but it doesn't. You'll need to redesign your system to not do this.
Protocols are existential types that is why you are confused. You need to expose to protocol types of your class Type. In your case you can do LowerProtocol or HigherProtocol so it prints 10 now. Let`s make like this
let lowerClass: LowerProtocol = LowerClass()
or
let lowerClass: HigherProtocol = LowerClass()
lowerClass.level // now prints 10
lowerClass.doSomething() // Prints "Lower level is 10" to the console.

Swift: casting un-constrained generic type to generic type that confirms to Decodable

Situation
I have a two generic classes which will fetch data either from api and database, lets say APIDataSource<I, O> and DBDataSource<I, O> respectively
I will inject any of two class in view-model when creating it and view-model will use that class to fetch data it needed. I want view-model to work exactly same with both class. So I don't want different generic constraints for the classes
// sudo code
ViewModel(APIDataSource <InputModel, ResponseModel>(...))
// I want to change the datasource in future like
ViewModel(DBDataSource <InputModel, ResponseModel>(...))
To fetch data from api ResponseModel need to confirms to "Decodable" because I want to create that object from JSON. To fetch data from realm database it need to inherit from Object
Inside ViewModel I want to get response like
// sudo code
self.dataSource.request("param1", "param2")
If developer tries to fetch api data from database or vice-versa it will check for correct type and throws proper error.
Stripped out version of code for playground
Following is stripped out version of code which shows what I want to achieve or where I am stuck (casting un-constrained generic type to generic type that confirms to Decodable)
import Foundation
// Just to test functions below
class DummyModel: Decodable {
}
// Stripped out version of function which will convert json to object of type T
func decode<T:Decodable>(_ type: T.Type){
print(type)
}
// This doesn't give compilation error
// Ignore the inp
func testDecode<T:Decodable> (_ inp: T) {
decode(T.self)
}
// This gives compilation error
// Ignore the inp
func testDecode2<T>(_ inp: T){
if(T.self is Decodable){
// ??????????
// How can we cast T at runtime after checking T confirms to Decodable??
decode(T.self as! Decodable.Type)
}
}
testDecode(DummyModel())
Any help or explanation that this could not work would be appreciated. Thanks in advance :)
As #matt suggests, moving my various comments over to an answer in the form "your problem has no good solution and you need to redesign your problem."
What you're trying to do is at best fragile, and at worst impossible. Matt's approach is a good solution when you're trying to improve performance, but it breaks in surprising ways if it impacts behavior. For example:
protocol P {}
func doSomething<T>(x: T) -> String {
if x is P {
return "\(x) simple, but it's really P"
}
return "\(x) simple"
}
func doSomething<T: P>(x: T) -> String {
return "\(x) is P"
}
struct S: P {}
doSomething(x: S()) // S() is P
So that works just like we expect. But we can lose the type information this way:
func wrapper<T>(x: T) -> String {
return doSomething(x: x)
}
wrapper(x: S()) // S() simple, but it's really P!
So you can't solve this with generics.
Going back to your approach, which at least has the possibility of being robust, it's still not going to work. Swift's type system just doesn't have a way to express what you're trying to say. But I don't think you should be trying to say this anyway.
In the method that fetch data I will check type of generic type and if it confirms to "Decodable" protocol I will use it to fetch data from api else from database.
If fetching from the API vs the database represents different semantics (rather than just a performance improvement), this is very dangerous even if you could get it to work. Any part of the program can attach Decodable to any type. It can even be done in a separate module. Adding protocol conformance should never change the semantics (outwardly visible behaviors) of the program, only the performance or capabilities.
I have a generic class which will fetch data either from api or database
Perfect. If you already have a class, class inheritance makes a lot of sense here. I might build it like:
class Model {
required init(identifier: String) {}
}
class DatabaseModel {
required init(fromDatabaseWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromDatabaseWithIdentifier: identifier )}
}
class APIModel {
required init(fromAPIWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromAPIWithIdentifier: identifier )}
}
class SomeModel: DatabaseModel {
required init(fromDatabaseWithIdentifier identifier: String) {
super.init(fromDatabaseWithIdentifier: identifier)
}
}
Depending on your exact needs, you might rearrange this (and a protocol might also be workable here). But the key point is that the model knows how to fetch itself. That makes it easy to use Decodable inside the class (since it can easily use type(of: self) as the parameter).
Your needs may be different, and if you'll describe them a bit better maybe we'll come to a better solution. But it should not be based on whether something merely conforms to a protocol. In most cases that will be impossible, and if you get it working it will be fragile.
What you'd really like to do here is have two versions of testDecode, one for when T conforms to Decodable, the other for when it doesn't. You would thus overload the function testDecode so that the right one is called depending on the type of T.
Unfortunately, you can't do that, because you can't do a function overload that depends on the resolution of a generic type. But you can work around this by boxing the function inside a generic type, because you can extend the type conditionally.
Thus, just to show the architecture:
protocol P{}
struct Box<T> {
func f() {
print("it doesn't conform to P")
}
}
extension Box where T : P {
func f() {
print("it conforms to P")
}
}
struct S1:P {}
struct S2 {}
let b1 = Box<S1>()
b1.f() // "it conforms to P"
let b2 = Box<S2>()
b2.f() // "it doesn't conform to P"
This proves that the right version of f is being called, depending on whether the type that resolves the generic conforms to the protocol or not.

Difference between using Generic and Protocol as type parameters, what are the pros and cons of implement them in a function

Since Swift allows us using both Protocol and Generic as parameter types in a function, the scenario below has come into my mind:
protocol AProtocol {
var name: String{ get }
}
class ClassA: AProtocol {
var name = "Allen"
}
func printNameGeneric<T: AProtocol>(param: T) {
print(param.name)
}
func printNameProtocol(param: AProtocol) {
print(param.name)
}
The first function uses generic as parameter type with a type constraint, and the second function uses protocol as the parameter type directly. However, these two functions can have the same effect, which is the point confusing me. So my questions are:
What are the specific scenarios for each of them (or a case which can only be done by the specific one, but not another)?
For the given case, both functions turn out the same result. Which one is better to implement (or the pros and cons of each of them)?
This great talk has mentioned generic specialization, which is a optimization that turn the way of function dispatching from dynamic dispatching (function with non-generic parameters) to static dispatching or inlining (function with generic parameters). Since static dispatching and inlining are less expensive in contrast with dynamic dispatching, to implement functions with generic can always provide a better performance.
#Hamish also gave great information in this post, have a look for more information.
Here is a new question came to me:
struct StructA: AProtocol {
var a: Int
}
struct StructB: AProtocol {
var b: Int
}
func buttonClicked(sender: UIButton) {
var aVar: AProtocol
if sender == self.buttonA
{
aVar = StructA(a: 1)
}
else if sender == self.buttonA
{
aVar = StructB(b: 2)
}
foo(param: aVar)
}
func foo<T: AProtocol>(param: T) {
//do something
}
If there are several types conform to a Protocol, and are pass in to a generic function in different conditions dynamically. As shown above, pressing different buttons will pass different types(StructA or StructB) of parameter into function, would the generic specialization still work in this case?
There is actually a video from this year's WWDC about that (it was about performance of classes, structs and protocols; I don't have a link but you should be able to find it).
In your second function, where you pass a any value that conforms to that protocol, you are actually passing a container that has 24 bytes of storage for the passed value, and 16 bytes for type related information (to determine which methods to call, ergo dynamic dispatch). If the passed value is now bigger than 24 bytes in memory, the object will be allocated on the heap and the container stores a reference to that object! That is actually extremely time consuming and should certainly be avoided if possible.
In your first function, where you use a generic constraint, there is actually created another function by the compiler that explicitly performs the function's operations upon that type. (If you use this function with lots of different types, your code size may, however, increase significantly; see C++ code bloat for further reference.) However, the compiler can now statically dispatch the methods, inline the function if possible and does certainly not have to allocate any heap space. Stated in the video mentioned above, code size does not have to increase significantly as code can still be shared... so the function with generic constraint is certainly the way to go!
Now we have two protocol below:
protocol A {
func sometingA()
}
protocol B {
func sometingB()
}
Then the parameter need to conform to both A and B.
//Generic solution
func methodGeneric<T:A>(t:T)where T:B {
t.sometingA()
t.sometingB()
}
//we need protocol C to define the parameter type
protocol C:A,B {}
//Protocol solution
func methodProtocol(c:C){
c.sometingA()
c.sometingB()
}
It seems that nothing is wrong but when we define a struct like this:
struct S:A,B {
func sometingB() {
print("B")
}
func sometingA() {
print("A")
}
}
The methodGeneric works but we need to change struct S:A,B to struct S:C to make methodProtocol work. Some questions:
Do we really need protocol C?
Why not would we write like func method(s:S)?
You could read more about this in the Generic Doc for additional information .

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.
I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.
My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.
Elaboration: I really have three goals here I want to achieve:
I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)
I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).
I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.
Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.
No! It can't be extended multiple times.
extension Int {
var add: Int {return self + 100} // Line A
}
extension Int {
var add: Int {return self + 105} //Line B
}
Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'
Swift is a static typing language and helps you find these sorts of errors before runtime
In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.
Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?
The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.
class baseClass {
//stuff
}
extension baseClass: myProtocol {
override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool
//protocol method code sets status as appropriate...
return status = true ? optOne(status) : optTwo(status)
}
func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}
func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}
extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}
extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}
I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.
You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.
We can solve the issue with a bit of generic magic.
class MyView: UIView {
var customizer: MyProtocol<MyView> = Defaults()
func willCallCustomizer() {
customizer.coolMethod(self)
}
}
// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
func coolMethod(_ view: T) {}
}
// Class inherits from the "protocol"
class Defaults: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// Some default behavior
}
}
/// on the clients end...
class CustomerCustomizer: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// customized behavior
}
}
So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.
myViewInstance.customizer = CustomerCustomizer()
The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.

How do I store data submitted to computed properties in a protocol extension?

In the app that I'm currently working on, I try to take advantage of the new protocol extension feature in Swift. The idea is that I have a lot of classes implementing the same protocol. Since all these classes should have the same computed properties, and since the properties should behave identically in de different classes, I thought it would be nice to add the functionality only once.
My code is structured as the following example
protocol SomeProtocol { ... }
// There could potentially be unlimited different versions of "SomeClass" that implements "SomeProtocol"
class SomeClass : SomeProtocol { ... }
extension SomeProtocol {
var computedProperty1: Type? {
get { getData(SOME_ENUM) }
set { validateAndSave(newValue, atKey: SOME_ENUM) }
}
var computedProperty2: Type? {
get { getData(SOME_OTHER_ENUM) }
set { validateAndSave(newValue, atKey: SOME_OTEHR_ENUM) }
}
...
func getData(atKey: ENUM_TYPE) -> Type? {
[NEED SOME WAY TO GET THE SAVED DATA AND RETURN IT]
}
func validateAndSave(value: Type?, atKey: ENUM_TYPE) {
[NEED SOME WAY TO SAVE DATA FOR LATER RETURNING]
}
}
// The properties needs to be visible to the client code like this:
class ClientCode {
let someClassObject: SomeProtocol = SomeClass()
someClassObject.computedProperty1 = Type()
print(someClassObject.computedProperty1)
}
(The code above shows signs of storing the data in different dictionaries, which was my first thought)
The problem is that an extension does not support stored properties. But where/how do I store the data submitted to the computed properties then?
I can think of 2 different solutions, but none of them good..
I could transform the extension into a class that implements SomeProtocol instead, and then make SomeClass a subclass of it. That would allow me to save the data in stored properties. But it would also require me to implement all the methods the protocol requires in the new class - and that makes absolutely no sense, since it's the different versions of SomeClass that should provide different functionality..
I could just drop the entire extension idea, and move all the properties into SomeProtocol. But that would require me to implement all the computed properties in all the different versions of SomeClass with identical functionality, and the whole point of my extension idea was to avoid writing the same implementation for the same properties over and over again..
Is there some completely easy logical solution that I have overlooked?
... or a nice way to save data in a protocol extension that I do not know about?
... or another way of obtaining the desired functionality?
... or should I just suck it up and use one of my not-so-pretty solutions?
Assuming I understand the question correctly to work around the fact that protocol extensions don't support stored properties you could extend NSObject and use the objective C runtime to store your properties.
import ObjectiveC
private var AssociationKey: UInt8 = 0
class YourStoredObject {
// Whatever object your are persisting
}
extension NSObject {
var yourStoredObject: (YourStoredObject)! {
get {
return objc_getAssociatedObject(self, &AssociationKey) as? YourStoredObject
}
set(newValue) {
objc_setAssociatedObject(self, &AssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}
protocol YourProtocol {
var yourStoredObject: YourStoredObject! { get set }
}
extension YourProtocol {
func customYourStoredObjectGetter() -> YourStoredObject {
return yourStoredObject
}
}
extension UILabel : YourProtocol {
func myExtendedFunc() {
// Get (and print) your object directly
print(yourStoredObject)
// Get your object through a protocol custom getter
print(customYourStoredObjectGetter())
// Set your object
yourStoredObject = YourStoredObject()
}
}
I'm not saying this is the best solution but this is the only solution I can think of. I'm also looking for nicer Swift alternatives but still have not found any.
Protocol extension? Why?
Sometimes we get so hung up on an idea that we ignore a practical solution staring right at our face.
1. Do you have set of computed properties? No, you want stored properties.
Since all these classes should have the same computed properties, and
since the properties should behave identically in de different
classes...
... but later
The problem is that an extension does not support stored properties.
But where/how do I store the data submitted to the computed properties
then?
2. Assuming that it is a set of stored properties that you want, you practically provided the solution yourself! Made one change that will make sense now.
I could transform the extension into a class that implements
SomeProtocol instead, and then make SomeClass a subclass of it. That
would allow me to save the data in stored properties.
You extend the class whenever you want to and then confirm its subclasses to SomeProtocol to get the features. This is cleaner.
On a side note, Swift's protocols not being able to store properties is by design. Protocols do not have existence in their own right and it doesn't make sense to add stored properties in them.