Will generics still be useful now that there are protocol extensions?

Generics were a powerful feature but protocol extensions are even more powerful and they can do almost anything generics could do.


What generics can do that protocol extensions can't?


(the only thing I see is using a generic that isn't constraint by anything, but that's not a common usecase)

Structs, classes and protocols can *all* be generic.


What generic structs and classes can do that protocols can't is be instantiated.

And, for example, try to write this global function using protocol extensions and no "generics":

func clamp<T: Comparable>(v: T, between minValue: T, and maxValue: T) -> T {
    return min(maxValue, max(v, minValue))
}


(Could someone please fix the issue with the random font sizes in this forum?)

Excactly. I think you're confusing something. Protocol extensions are made powerful by the generic type system. Without generics, they wouldn't really be all that helpful as they would basically boil down to simply type extensions and hetergenous collection usage.


As Jens' example points out above, you cannot write that code without generics, but you can write it without protocol extensions.

This seems to work:

extension Comparable {
    func clamp(min minVal:Self, max maxVal:Self)->Self{
        if self < minVal {return minVal}
        if maxVal < self {return maxVal}
        return self
    }
}

: ) That's why I said global function.


And then, I realize that you can write:

extension Comparable {
    static func clamp(v: Self, between minValue: Self, and maxValue: Self) -> Self {
        if v < minValue { return minValue }
        if maxValue < v { return maxValue }
        return v
    }
}

print( Float.clamp(1.2, between: 3.4, and: 5.6) )


So ok, you win, sort of.

Well, now I am confused. Isn't part of the point of protocol extensions that we don't have to deal with global functions as much anymore?


Both of our examples work only with items which adhere to Comparable, but the extension:

1) Is discoverable via autocomplete

2) Doesn't clutter up the global namespace with something that only works for comparable


What does the global function give you that the extension doesn't (besides the difference in syntax)?


I think I am missing an important idea here somewhere...

Operators are global functions.

Yes, part of the point of protocol extensions IS that we don't have to deal with global functions. And it results, as you said, in cleaner namespaces and more elegants calls.


To confirm this, we can just look at the std lib that went from 101 global functions to 77. But will they reduce that number even more and can it reach 0?

I agree with this but I don't see how it gives generics abilities to do things that protocol extensions can't do.

Protocol extensions are extremly powerful without generics!


They allow to do what was impossible in OOP: kind of multiple inheritance. And, as they are presented in the session 'Protocol Oriented Programing' (excellent session btw), they even open up a new paradigm. I suggest you check it out, it's really a blast.

Conceptually speaking, `Self` is an implicit type parameter which you give values by implementing the protocol on different types. So, for any generic function, you can "eliminate" one type parameter by making it the `Self` type of a static protocol extension method. This doesn't eliminate generics for generic functions with multiple type parameters, though. In order to do that, you'd need to bundle the types into the `Self` type as associated types. This is ugly, because it means that you need to create named types to bundle each potential combination of type parameters. Plus, it doesn't play very well with type inference, since you always have to specify the type bundle (`Self` type) you're using—i.e. explicitly specify the type parameters. You can't just directly call the protocol method and have it work backwards from the argument types to get the `Self` type the way you can if you use explicit generics.

Multiple inheritance isn't supported in ObjC or Swift, but that doesn't mean it's impossible in OOP; C++ has supported multiple inheritance for a LONG time.


Anyhow, you missed my point.

Generics allow you to constrain to specific, homogeneous types.

func foo<T>(items: [T]) { ... }


Items must be an array made up of items of T.


func foo(items: [T]) { ... }


If T is a protocol, then items can be an array made up of anything that conforms to T. This was talked about in the talk when walking through the historical issues with OOP.


Another example where the combination of protocol extensions and a generic type system really compliment one another:


extension Equatable where Self : Drawable {
    func isEqualTo(other: Drawable) -> Bool {
        guard let o = other as? Self else { return false }
        return self == o
    }
}


That protocol extension is not possible to write without generics.

Will generics still be useful now that there are protocol extensions?
 
 
Q