Skip to Content
Course content

224: Common Swift Interview Questions on Generics

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I’ve sat through dozens of technical interviews, and there is one specific moment where I can tell a candidate understands Generics and where they are just guessing. It usually happens when I ask them to write a simple utility function to find a duplicate in an array. They'll start typing quickly, confident that T is just a placeholder for "whatever the user passes in," only to be stopped cold by a compiler error they didn't expect.

The Myth: "Generics are just a flexible version of Any"

The most common misconception I see is the belief that a generic type parameter (like T) behaves like Any. People think that because T can be anything, you can do anything to it. Let's look at why that's wrong. Consider this attempt at a function that checks if an array contains any duplicate elements:

func hasDuplicates<T>(items: [T]) -> Bool {
    for (index, item) in items.enumerated() {
        // This line will cause a compiler error!
        if items[index + 1...] .contains(item) { 
            return true
        }
    }
    return false
}

If you try to compile this, Swift will yell at you: Binary operator '==' cannot be applied to operands of type 'T' and 'T'. Why? Because to the compiler, T is a total mystery. It could be a String, an Int, or a CustomUserSession object that doesn't support equality checks. You can't use == or contains() because those require the type to be Equatable. Any allows you to store anything, but it strips away the type's identity; T preserves the identity, but it doesn't grant you powers the type doesn't actually have.

The Reality: Constraints are the Real Power

The key to passing the "Generics" portion of a Swift interview isn't knowing how to write <T>; it's knowing how to constrain it. When you tell Swift that T: Equatable, you aren't just adding a rule—you're unlocking a whole set of capabilities that the compiler now guarantees are safe.

Here is the corrected version of that duplicate check. Notice how the constraint changes everything:

func hasDuplicates<T: Equatable>(items: [T]) -> Bool {
    for (index, item) in items.enumerated() {
        if items[(index + 1)...].contains(item) {
            return true
        }
    }
    return false
}

I always tell my juniors: think of constraints as a contract. By saying T: Equatable, you're telling the compiler, "I don't care what this type is, as long as it knows how to compare itself to another instance of itself."

Handling Complex Requirements with the 'where' Clause

In more senior-level interviews, you'll likely be asked about scenarios where a simple T: Protocol isn't enough. For instance, what if you have a function that compares two different generic types, but only if they both share a common trait? This is where the where clause comes in.

Imagine you're building a system that compares two different types of "Version" objects (maybe a ServerVersion and a ClientVersion) to see if they are compatible. You can't just use T because the two inputs might be different types entirely.

func areCompatible<T, U>(versionA: T, versionB: U) -> Bool where T: Versionable, U: Versionable {
    return versionA.majorVersion == versionB.majorVersion
}

The where clause allows you to define complex relationships. You can constrain the association between types, which is a huge step up from basic generic syntax. If you can demonstrate this in an interview, you're showing that you understand how to maintain type safety without sacrificing the flexibility of your API.




📋 Practical Task

Implementing a Type-Safe Generic Response Wrapper

In professional Swift development, we often wrap API responses in a generic Result-style object to handle success and failure consistently across different data models.

Your Task: Create a generic struct named NetworkResponse. It should have the following requirements:

  • It must be generic over a type T.
  • It should have a property data: T? and a property statusCode: Int.
  • Implement a method called isSuccessful() -> Bool that returns true if the statusCode is in the range 200-299.
  • Implement a second method called validateData() -> Bool. This method should only be available if the generic type T conforms to the Equatable protocol. It should take a parameter expectedValue: T and return true if data matches the expectedValue.

Hint: You will need to use a where clause on the validateData method extension to ensure it only exists for Equatable types.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.