inheritance and polymorphism in swift - swift

I have the following problem:
Class A - super class.
Class A protocol:
has method ->
func test(params: GeneralParams, completionBlock: GeneralCompletionBlock)
GeneralParams is super class and has the following 2 subclasses: BParams, CParams.
now i have 2 more classes:
class B: A, A protocol
class C: A, A protocol
I want class B, C to use test function but with different class for their params for class B i want to use BParams and different completion block and for C the same thing. i want to have the same method for both with different parameters and implementation for both.
Whats the best solution for this situation?

Since Swift allows method overload, the best practice here would be to overload a method to suite your needs in a new class.
For instance:
class B: A{
func test(params: BParams, completionBlock: GeneralCompletionBlock){
...
}
}
class C: A{
func test(params: CParams, completionBlock: GeneralCompletionBlock){
...
}
}

I want class B, C to use test function but with different class for their params
The most important rule of subclassing is substitutability. If B is a kind of A, then everywhere an A can be used, it must be legal to use a B. So every subclass of A must support this method:
func test(params: GeneralParams, completionBlock: GeneralCompletionBlock)
It cannot restrict this method to other types (not even to subtypes of these). If it did, then there would be places that I could use A, but couldn't use B.
B is free to extend A and add new methods. So, as #tmac_balla suggests, you can add an overload that will be selected for subtypes. For example:
class AParam {}
class BParam: AParam {}
class A {
func f(param: AParam) {print("A")}
}
class B: A {
func f(param: BParam) {print("B")}
}
B().f(AParam()) // "A"
B().f(BParam()) // "B"
But B must still support being passed the superclass.
Most of the time in Swift, this is the wrong way to go about things. Subclassing introduces lots of complexity that you usually don't want. Instead you generally want protocols and generics in Swift. For example, rather than A, B, and C, you would just have a generic A and a protocol.
protocol Param {
var name: String { get }
}
struct AParam: Param {
let name = "A"
}
struct BParam: Param {
let name = "B"
}
struct S<P: Param> {
func f(param: P) {print(param.name)}
}
let a = S<AParam>()
a.f(AParam()) // "A"
// a.f(BParam()) // error; we've restricted the type it can take
let b = S<BParam>()
b.f(BParam()) // "B"

Related

Swift generic T.Type becomes T.Protocol

Swift 5.1
I'm writing a class that has a generic parameter T, and one of its methods accepts a type as an argument, where the type extends from T.Type. See foo1 below:
public protocol P {
}
public class C: P {
}
public class X<T> {
public func foo1(_ t: T.Type) { // The function in question
}
public func foo2(_ t: P.Type) { // Note that this works as expected, but is not generic
}
}
public func test() {
let x = X<P>()
x.foo1(C.self) // ERROR Cannot convert value of type 'C.Type' to expected argument type 'P.Protocol'
x.foo2(C.self) // Works as expected, but is not generic
}
Now, foo1 works fine when T is a class. However, when T is a protocol (e.g. P), Swift seems to rewrite my function signature from T.Type to T.Protocol.
Why did it do this?
How do I instead get foo1 to accept a type that inherits from P?
Class X is used in a number of other places - any changes to it must not restrict or remove class parameter T nor reduce X's functionality, nor make explicit reference to C or P. (It would be acceptable to constrain T to exclude protocols that do not extend AnyObject; I don't know how to do that, though. It might also be acceptable to e.g. create a subclass of X that adds the ability to handle a protocol in T, but I'm not sure how to do that, either.)
For clarity, this class is used to register classes (t) that conform to some specified parent (T), for more complicated project reasons. (Note that classes are being registered, not instances thereof.) The parent is given at the creation of X, via the type parameter. It works fine for a T of any class, but I'd also like it to work for a T of any protocol - or at least for a T of any protocol P: AnyObject, under which circumstances foo1 should accept any subclass of P...the same way it works when T is a class.
Even though C is a P, but C.Type != P.Type, so the error.
But generics works in a bit different way, like in below examples:
public class X {
public func foo1<T>(_ t: T.Type) { // this way
}
public func foo3<T:P>(_ t: T.Type) { // or this way
}
public func foo2(_ t: P.Type) { // Note that this works as expected, but is not generic
}
}
public func test() {
let x = X()
x.foo1(C.self) // << works
x.foo3(C.self) // << works
x.foo2(C.self) // Works as expected, but is not generic
}

Why does a mutating method in a Swift protocol infinitely recurse unless only an extension method?

I came across the following code in SR-142 on bugs.swift.org.
If a protocol has an extension method that's mutating, a class instance can call the mutating function without any problem.
// protocol definition
protocol P { }
extension P {
mutating func m() { }
}
// class conforming to P
class C : P {
// redeclare m() without the mutating qualifier
func m() {
// call protocol's default implementation
var p: P = self
p.m()
}
}
let c = C()
c.m()
If I make a small change to add the method to the protocol declaration:
protocol P {
mutating func m() // This is what I added.
}
extension P {
mutating func m() { }
}
class C : P {
func m() {
var p: P = self
p.m()
}
}
let c = C()
c.m() // This one is calling itself indefinitely; why?
Why does c.m() keep calling itself again and again?
With your change in the second example, by including the m in the protocol definition, that instructs Swift to employ dynamic dispatch. So when you call p.m(), it dynamically determines whether the object has overridden the default implementation of the method. In this particular example, that results in the method recursively calling itself.
But in the first example, in the absence of the method being part of the protocol definition, Swift will employ static dispatch, and because p is of type P, it will call the m implementation in P.
By way of example, consider where the method is not part of the protocol definition (and therefore not in the “protocol witness table”):
protocol P {
// func method()
}
extension P {
func method() {
print("Protocol default implementation")
}
}
struct Foo: P {
func method() {
print(“Foo implementation")
}
}
Because the foo is a P reference and because method is not part of the P definition, it excludes method from the protocol witness table and employs static dispatch. As a result the following will print “Protocol default implementation”:
let foo: P = Foo()
foo.method() // Protocol default implementation
But if you change the protocol to explicitly include this method, leaving everything else the same, method will be included in the protocol witness table:
protocol P {
func method()
}
Then the following will now print “Foo implementation”, because although the foo variable is of type P, it will dynamically determine whether the underlying type, Foo, has overridden that method:
let foo: P = Foo()
foo.method() // Foo implementation
For more information on dynamic vs static dispatch, see WWDC 2016 video Understanding Swift Performance.
By declaring m in the protocol & providing implementation in your class, it over writes the default implementation.
But in the first example when you cast your class as protocol it will call protocol's default implementation because the implementation of the class is it own and not over writing any of the protocol's method

How should I write this in Swift?

Let's say that I create a protocol like this:
protocol A {
associatedtype T
func computeSomething(with:T) -> Double
}
In my generic typed class, I would like to do something like this:
class B<U> {
var doSomething:A<U>
}
This thing is that this generates an error, but I would like to accept any type that would support computeSomething on my type U but I don't know at all how to do that?
Edit for clarity
Basically if A was a generic struct or class, that would be possible, but what if no default implementation (provided by class or struct) makes sense here and the only thing I want is to ensure that the type does what I want?
Edit #2 (with concrete example)
I wanted to simplify my question which makes it pretty hard to understand so here is a still simplified and fictional problem that probably matches better the issue I am encountering:
I am writing a generic class that processes its generic type T:
class Process<T> { ... }
The class Process itself includes code that processes T, but in order for this code to work, it needs T to conform to some protocols, for instance:
protocol A {
func mixWith(other:A) -> A
}
protocol B {
var isFoo:Bool { get set }
}
So my first approach was to simply require T to conform to those protocols:
class Process<T:<A,B>> { ... }
This looks like the simplest approach and probably is in many cases, but in my case I think that this actually is problematic, for this reason:
First, I may need to process the same type in many different ways, and changing a way a type is being processed often requires changing the actual implementation of protocols A and B for instance in this case, fooProcess and barProcess are both of type Process with generic type MyType:
let fooProcess = Process<MyType>()
let barProcess = Process<MyType>()
But I want fooProcess and barProcess to do different operations which in many cases would require to change the implementation of the A and B protocols of my MyType type and that's simply not possible.
So my first idea was to simply require some closures and variables to be defined so that I wouldn't need protocols anymore and would define the way data is being processed only in my Process class, a little bit like this:
class Process<T> {
//
var mix:(_ lhs:T, _ rhs:T)->(T)
var isFoo:(_ a:T)->(Bool)
...
}
There all of the processing would be directly implemented in my Processing class, again this would have looked like the right solution but now comes another issue, which led me to my associated type approach: it turns out that in many cases, the user of my Process class would want to get some default behaviour implemented by my framework, for instance, I could automatically implement protocol A and B for them as long as their class conformed to protocol X, here is how it did it:
protocol X:A,B {
...
}
extension protocol X {
// Here was my default implementation of A and B, which enabled my user to directly get A and B implemented as long as their type conformed to X
}
By using this method, I would let my user directly choose what they wanted to implement themselves, by conforming to protocol X they would only need to write a little bit of code and let my framework to all of the rest by itself, and if they wanted to implement themselves A or B they still could.
So if I am right, there is no way to do such a thing with my closures implementation.
So for this reason, I thought that an associated type protocol would be a good solution because here I could let my users easily get some default behaviour or write their own, so now we are getting back to my original question:
protocol AProcessing {
associatedtype U
func mix(_ lhs:U, _ rhs:U) -> U
}
protocol BProcessing {
associatedtype U
func isFoo(_ a:U) -> Bool
}
And then do something like that:
class Process<T> {
var aProcessor:AProcessing<T>
var bProcessor:BProcessing<T>
}
Here the advantage compared to closures is that I could write a special class conforming to AProcessing that could provide default implementation, this way:
class AutomaticAProcessing<T:X>:AProcessing { ... }
That would have enabled my users to so something like that:
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing<SomeType>()
processData.bProcessor = TheirOwnImplemtation
Not only is this not possible in Swift, but it also feels like I am using too many "hacks" to get things done and there should be an easier language feature to do that, unfortunately I don't know what I should use.
I don't think it is possible, because the generic type of the protocol is specified in the class that implements it.
You could write something like this:
class B<U, P: A> where P.T == U {
var someVar: P?
}
But then you would need to specify a second parameter with the specific class. For example:
class C: A {
typealias T = String
func computeSomething(with: String) -> Double {
return 0.0
}
}
let b = B<String, C>()
let c = b.someVar
But it can't return a protocol with specific type in its associatedtype
One way would be to start with an empty generic struct, and then extend it on types where it makes sense:
struct A<T> {}
extension A where T: Base {
func computeSomething(with: T) -> Double {
return 1
}
}
Usage:
protocol Base {}
class B<U: Base> {
let doSomething = A<U>()
func foo(x: U) -> Double {
return doSomething.computeSomething(with: x)
}
}
class Z : Base {}
let x = B<Z>()
let y = x.foo(x: Z())
print(y)
To EDIT #2:
Remove associated types, and it should be workable:
protocol A {}
protocol B {}
protocol AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A
}
protocol BProcessing {
func isFoo(_ a: B) -> Bool
}
Then, your processor:
class Process<T: A & B> {
var aProcessor: AProcessing!
var bProcessor: BProcessing!
func foo(_ a: T) -> Bool {
let x = aProcessor.mix(a, a)
guard let b = x as? B else { return false }
return bProcessor.isFoo(b)
}
}
And usage:
struct AutomaticAProcessing : AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A { return lhs }
}
struct TheirOwnImplemtation : BProcessing {
func isFoo(_ a: B) -> Bool { return false }
}
struct SomeType : A, B {}
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing()
processData.bProcessor = TheirOwnImplemtation()
let x = SomeType()
let y = processData.foo(x)
print(y)

Generic Constraints and Initializer Inheritance in Swift

I am trying to call an initializer required by protocol A on a type that both conforms to A and is a subclass of C.
All is fine and good if C is a base class. But as soon as C subclasses another class, say B, it breaks.
Here's what I am talking about:
protocol A {
init(foo: String)
}
class B {
init() {}
}
class C: B {}
func makeSomething<T: A>() -> T where T: B {
return T(foo: "Hi")
}
That works. But if I change where T: B to where T: C, I get the following error: argument passed to call that takes no arguments. It will only allow me to call Bs init.
Why can't I call this initializer? I understand that the super class has its own designated initializers that must be called. But that will be enforced when someone actually writes the class that subclasses B and conforms to A. (E.g. implementing init(Foo: String) and calling super.init(bar: Int) inside).
Any help here would be greatly appreciated. Thanks!
Swift provides a default initializer for your base class if it has all properties initialized but not incase of Generics because Swift may think its properties has not been initialized.
So when you constraint your return type as
func makeSomething<T: A>() -> T where T: C
It requires initialization for class C as Swift cannot provide a default initializer.But if your remove the where clause everything works fine
func makeSomething<T: A>() -> T {
return T(foo:"string")
}
If you want to return return T(foo: "Hi") :
You are getting error because class C doesn't have initializer that accepts init(foo: String)
Change your class C as
class C: A {
required init(foo: String) {
}
}
which provides at least one initializer that accepts the argument type.
So, remember if you don't subclass There is already one initializer doing your job and you dont get error.

Check type of generic class without respecting generic type constraint

I have the following structure:
class A
class A<T: SomeInterface> : C {
}
class B
class B : SomeInterface {
func someFunc(param: C){
// check if param is of class A with `self.dynamicType` generic type
if let typedC = param as? A<self.dynamicType> { // does not work
}
}
}
I would like to check if param has a class of type B as a generic constraint. Is there a way to specify a wildcard generic type ? It is not of importance whether the generic constraint in fact is of type B or not, but this wouldn't be possible either:
class B : SomeInterface {
func someFunc(param: C){
// check if param is of type A
if let typedC = param as? A { // don't check generic constraint type
}
}
}
or (in case there is a wildcard):
class B : SomeInterface {
func someFunc(param: C){
// check if param is of type A with wildcard (Is there such a thing as a wildcard?)
if let typedC = param as? A<?> { // don't require specific generic type, just enter if param is of type A
}
}
}
EDIT - Playground sample
import UIKit
protocol SomeInterface{
func someFunc(param: C)
}
class C {
}
class A<T: SomeInterface> : C{
}
class B : SomeInterface {
func someFunc(param: C) {
// A is a subclass of C, but I want the typed generic subclass
if let typed = param as? A<self.dynamicType> {
}
}
}
let b = B()
let a = A<B>()
b.someFunc(a)
It is hard to express how complicated the world gets once you start allowing non-final subclasses. If you can possibly make these final classes or protocols, many little sharp edges will go away.
What you say you want and the code you're writing don't really line up (which is very common when dealing with subclasses). So it matters what you really want.
I would like to check if param has a class of type B as a generic constraint.
Sure. That's easy.
class B : SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<B> {
print(typed)
} else {
print("NO")
}
}
}
This will work anytime we get an A<B>. It will not work if we receive A<SubClassOfB>, even if that's passed to SubclassOfB.someFunc(). (See what I meant about it being subtle?)
From your code, you seem to actually want "if I'm passed A<Self>" where "Self" means "exactly my class, not a superclass or subclass." The only way I've ever seen that done is with a protocol extension:
extension SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<Self> {
print(typed)
} else {
print("NO")
}
}
}
This allows Self to be replaced with "my class." But note that this means someFunc(A<MySubclass>) won't work. A<Self> is not the same thing as A<Subclass>. Note that you can add a where clause to the extension to limit its scope:
extension SomeInterface where Self: B { ... }
If you mean "T is either Self or some subclass of Self", maybe it's possible, but in my experience it gets more and more tricky and fragile. You can't make generic types covariant on their parameters in Swift, so A<Subclass> is not itself a subtype of A<Superclass> (that's a much trickier problem than it sounds like, and you wouldn't always want it to be true). This is the kind of crazy corner case that goes away if you'll just mark B as final. Then most of the rat's nest goes away.
When you define:
class A<T: SomeInterface>{
}
you are not defining a class, and so a type, but a generic type A, that must be instantiated to become some type.
So, you cannot define inside another class a function in this way:
func someFunc(paramA: A)
This will give always a type error. Instead you should define:
func someFunc(paramA: A<SomeTypeSubtypeOfSomeInterface>)
For instance, since you have defined B as subtype of SomeInterface, you could define:
func someFunc(paramA: A<B>)