Swift Protocols vs. Other Languages’ Interfaces: Understanding the Differences

KD Knowledge Diet
3 min readJan 29, 2024

In the realm of programming, the concept of defining a set of methods and properties that other types must implement is not unique to Swift. Many languages have a similar construct, often known as an ‘interface.’ However, Swift’s protocol is more than just an interface, and understanding the distinctions can empower developers to make better design decisions.

Swift Protocols: Beyond Traditional Interfaces

At first glance, Swift protocols may seem analogous to interfaces in languages like Java or C#. However, Swift protocols come with features that provide additional power and flexibility:

  1. Value Semantics: Swift protocols can be adopted by structs and enums, which are value types, not just classes (reference types). This is a significant departure from languages like Java, where interfaces can only be implemented by classes.
  2. Extensions: Protocols in Swift can be extended to provide default implementations of methods, something traditional interfaces cannot do. This allows for code reuse without the need for inheritance or utility classes.
  3. Protocol Composition: Swift allows protocols to be composed together using the ‘&’ operator, enabling types to conform to multiple protocols at once and ensuring a level of flexibility that’s not as easily achievable with classic interfaces.
  4. Associated Types and Self Requirements: Protocols in Swift can specify requirements for associated types and enforce that methods return an instance of the conforming type (using ‘Self’), adding a layer of type safety and customization.

Interfaces in Other Languages

In contrast, interfaces in languages like Java and C# generally define a contract that classes must follow, without providing any implementation details. This enforces a rigid structure but lacks the flexibility that Swift protocols offer.

  1. Single Inheritance: Classes in these languages can only inherit from one base class but can implement multiple interfaces. This can lead to the diamond problem, which Swift avoids with protocol composition.
  2. No Default Implementation: Interfaces traditionally do not contain any implementation logic, which means each class must provide its own implementation for every method, potentially leading to duplicate code.
  3. Reference Semantics Only: Since interfaces are tied to classes, they are limited to reference semantics, which can have implications for performance and thread safety.

A Comparative Example

Here’s how a Swift protocol with an extension looks compared to a Java interface:

Swift Protocol with Extension:

protocol Drawable {
func draw()
}

extension Drawable {
func draw() {
print("Default drawing")
}
}

Java Interface:

interface Drawable {
void draw();
}

class Circle implements Drawable {
@Override
public void draw() {
// Must provide an implementation
System.out.println("Circle drawing");
}
}

In Swift, all types conforming to Drawable can use the default draw method without additional code. In Java, every class that implements Drawable must provide its own draw method, even if the implementation is identical across classes.

Conclusion

While Swift’s protocols share conceptual similarities with interfaces from other languages, they offer a broader set of features that promote more flexible and reusable code designs. By allowing default implementations, value semantics, and protocol composition, Swift protocols provide a level of expressiveness that fosters cleaner, more maintainable codebases. Understanding these differences is crucial for developers who are transitioning between Swift and other object-oriented languages, as it allows them to leverage the strengths of each language’s approach to type abstraction and code organization.

--

--

KD Knowledge Diet

Software Engineer, Mobile Developer living in Seoul. I hate people using difficult words. Why not using simple words? Keep It Simple Stupid!