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:

  • Swift Covariant Generics
  • How is a type-erased generic wrapper implemented?
  • Is it possible to restrict a Swift generic class function return type to the same class or subclass?
  • Implementing Set.addSequence in Swift
  • Default parameter as generic type
  • How to pass UITableView IndexPath to UIButton @selector by parameters in iOS?
    1. What are the specific scenarios for each of them (or a case which can only be done by the specific one, but not another)?

    2. 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
    }
    
    1. 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?

    2 Solutions Collect From Internet About “Difference between using Generic and Protocol as type parameters, what are the pros and cons of implement them in a function”

    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 conform 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()
    }
    

    seems nothing wrong but when we define a struct like this:

    struct S:A,B {
        func sometingB() {
            print("B")
        }
    
        func sometingA() {
            print("A")
        }
    }
    

    methodGeneric works but we need change struct S:A,B to struct S:C to make methodProtocol work. so questions come:

    1. we really need protocol C?
    2. why not write like func method(s:S)?

    you can read Generic Doc for more information .