Explanatory examples of protocol benefits vs Java interfaces?

One thing I don't fully understand in Swift is why protocols are the way they are. I know they are both similar to and different from Java interfaces. The similar part I understand, and I find Java interfaces relatively easy to understand. It's the differences that have me scratching my head. For example, a protocol can't always be used like a type because it "doesn't conform to itself".

I've seen questions and answers about this topic before, but the answers didn't have example code and used terms that I don't understand well (like "existential types" or "value abstracted types"). So, can someone show or link to example code that demonstrates the value of this difference? In other words: some things you can do with Swift protocols that you can't do with Java interfaces.

1 Like

Here are some things Swift's protocols can do, that Java's interfaces can't:

  1. Swift's interfaces can express a wider variety of requirements of conforming types, such as
    1. initializers (e.g. init(from: Decoder) in Decodable)
    2. static (or class) methods
    3. operators (e.g. == in Equatable)
    4. subscripts (e.g. subscript(Self.Index) -> Self.Element in RandomAccessCollection)
  2. Conditional conformance (Array is Equatable only if its Element type is Equatable)
  3. Default implementations (Implemented in Java 8)
  4. Conditional default implementations (not yet possible in Java)

As far as understanding existential goes, I would suggest @cocoaphony's series of blog posts on protocols: https://robnapier.net/start-with-a-protocol

3 Likes

Thanks, that helps. I'll add:

  1. Make a type conform by writing an extension. No need to change the type's original code.

Points 1.1 and 1.2 are what I was most confused about. They lead to the "P does not conform to P" errors. I was looking for example code that showed why those features are worth having, and the linked articles do provide some.

Another subtle thing that Swift protocols can express, but Java interfaces can’t, is “this method can be performed on two things of the same conforming type”. For instance, Swift’s Comparable has a static (operator) method which takes the parameters (Self, Self), meaning that you can compare an Int to an Int, or a String to a String, or a Person to a Person, but you can’t compare an Int to a Person. Java works around its lack of this feature by making its Comparable generic, but then classes can accidentally give themselves asymmetric comparisons, and (because Java generics use type erasure) it’s often possible to try to compare incompatible types anyway. Swift defines away these problems.

Protocols, and Swift generics in general, include a lot of features oriented towards very precisely declaring the relationships you expect different types to have to each other. The effect of this is that often you literally cannot write certain kinds of mistakes. Things you’d need to include unit tests for in other languages just cannot be expressed at all in Swift.

3 Likes

Yeah, I like that. It looks like what I saw with Haskell type classes when I dabbled in that language. But if I remember right they don't have subtyping, which causes things to get little more complicated here.

It appears that with Swift, if you do have subclasses and multiple implementations of ==, then it will pick which one to call based on the static type of the arguments, as opposed to Java which will use the run time type of the first argument.

These may be easier to understand if you don't view protocols as types. For example:

protocol Thing { }

var p: Thing

Instead of reading this declaration as “the type of p is Thing”, read it as “p can hold an instance of any type that conforms to Thing”.

In other words, even though you can't instantiate Thing because it's a protocol, there exists at least one type that conforms to it and whose instances you can assign to p.

The confusion arises because the type annotation for the existential “any type that conforms to Thing” is simply Thing. See Improving the UI of generics for a possible solution.

2 Likes
Terms of Service

Privacy Policy

Cookie Policy