# Switching on protocols

**URL:** <https://forums.swift.org/t/switching-on-protocols/82002>\
**Category:** Using Swift\
**Tags:** protocols, switch\
**Created:** [September 7, 2025, 8:26pm UTC](https://forums.swift.org/t/switching-on-protocols/82002 "2025-09-07T20:26:28Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![stever](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stever/32/42752_2.png) [@stever](https://forums.swift.org/u/stever)\
**Post date:** [September 7, 2025, 8:26pm UTC](https://forums.swift.org/t/switching-on-protocols/82002/1 "2025-09-07T20:26:28Z")

</div>

Hey everyone,

I ran into an unusual situation and I’m wondering why it is the way it is and what’s the best practice for this case.

Say I have a factory function that spits out concrete types when requested a protocol:

```swift
func get<T>() -> T?

```

And say I have these definitions and a way to call the function:

```swift
protocol Something {}
class SomethingImpl: Something {}

let result: Something? = get()

```

I found that I can implement it using `if` statements like this:

```swift
func get<T>() -> T? {
    if T.self == Something.self {
        return SomethingImpl() as? T
    }
    return nil
}

```

But using a switch in a seemingly similar fashion **doesn’t compile** :

```swift
func get<T>() -> T? {
    switch T.self {
    case Something.self: // Type of expression is ambiguous without a type annotation
        return SomethingImpl() as? T
    default:
        return nil
    }
}

```

The compiler error suggests that I need to specify the type of `Something.self` more precisely but I’m not sure how I could? Is that a case where the compiler error is inaccurate?

Looking at older code I found that using `case is` is one way to do it and it works for concrete types but it **silently fails for protocols**.

```swift
func get<T>() -> T? {
    switch T.self {
    case is Something.Type: // Never matches
        return SomethingImpl() as? T
    case is Int.Type:
        return 123 as? T
    default:
        return nil
    }
}

let something: Something? = get() // nil
let int: Int? = get() // Optional(123)

```

I did end up finding a solution that works in a way that’s closer to my first intuition by using ObjectIdentifier, but it feels a bit like doing the languages’ job, is it?

```swift
func get<T>() -> T? {
    switch ObjectIdentifier(T.self) {
    case ObjectIdentifier(Something.self):
        return SomethingImpl() as? T
    default:
        return nil
    }
}

```

---

<div class="post-metadata">

**Author:** ![stever](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stever/32/42752_2.png) [@stever](https://forums.swift.org/u/stever)\
**Post date:** [September 10, 2025, 4:35am UTC](https://forums.swift.org/t/switching-on-protocols/82002/3 "2025-09-10T04:35:47Z")

</div>

I got to play with this some more and sure enough that `case is (any Something).Type` does the trick.

On first read I thought `any Something` would mean “any type that is either Something or another type that conforms to Something”. But I tried it and it does only matches if I pass Something.self, as desired.

I’m still unsure why it has to be `any Something`. I don’t want just _any_ Something, I want _the_ `Something.Type` very specifically. The `if` equality check has no issues with this, so it sounds like the switch pattern matching is what accounts for the difference in syntax. That certainly tripped me up.

That example I gave is admittedly contrived and the real factory I’m working on has many different protocols. I hadn’t thought of the overloading possibility and tried it but in my case I think that ends up being more verbose than a simple switch.

Thanks @Danny!

---

<div class="post-metadata">

**Author:** ![Gero](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gero/32/23571_2.png) [@Gero](https://forums.swift.org/u/Gero)\
**Post date:** [September 10, 2025, 12:03pm UTC](https://forums.swift.org/t/switching-on-protocols/82002/4 "2025-09-10T12:03:47Z")

</div>

> [@stever](#):
>
> I’m still unsure why it has to be `any Something`. I don’t want just _any_ Something, I want _the_ `Something.Type` very specifically.

on that specifically: There _is_ no _type_ `Something`. Protocols are not types in Swift, they’re basically just meta-information _about_ types (that conform to them).

However, since we often need to specify a type of which we _only know that it conforms to a protocol_ we have existentials. Those are “box-types” that can hold _any_ type that conforms to a specific protocol. Historically we expressed that by just putting the protocol identifier where we’d usually place the type identifier in code. That’s why _sometimes_ you can write `Something.self`.

The modern way to specify an existential is `any Something` and it seems that in the pattern matching that a switch case does, it is required (note that the switch case matching mechanism is not exactly the same as an equality check like in the if statement).

I’d prefer the if-statement in this case as you’re avoiding an existential completely here. The function is already generic, after all, so you have a _specific_ type (which can in other scenarios also be specified as `some Something`, btw), so you really do want an equality check. On the other hand, you don’t really have an instance of an existential anyway, it’s just the type, so using pattern matching probably doesn’t introduce any indirection overhead… hm…

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [September 10, 2025, 6:23pm UTC](https://forums.swift.org/t/switching-on-protocols/82002/6 "2025-09-10T18:23:33Z")

</div>

> [@Danny](#):
>
> Best practice is overloading. Does that not work for you?
> 
> ```swift
> func get() -> (some Something)? { SomethingImpl() }
> func get<T>() -> T? { nil }
> 
> ```
> 
> ```swift
> #expect(get() as (any Something)? is SomethingImpl)
> #expect(get() is SomethingImpl)
> #expect(get() as Int? == nil)
> 
> ```

The original program did a dynamic check, whereas overloads are selected at compile time, so they're not the same.

But perhaps another approach OP should consider is this:

```swift
protocol Factory {
  associatedtype Instance
  func get() -> Instance
}

func get<F: Factory>(_ factory: F) -> F.Instance {
  return f.get()
}

```

Then you define various types to conform to `Factory`, instead of passing around existential metatype values.

---

<div class="post-metadata">

**Author:** ![stever](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stever/32/42752_2.png) [@stever](https://forums.swift.org/u/stever)\
**Post date:** [September 11, 2025, 2:20am UTC](https://forums.swift.org/t/switching-on-protocols/82002/8 "2025-09-11T02:20:29Z")

</div>

This is all very informative. My apologies for trimming a bit too much of my use case.

I’m just looking into using the factory pattern to inject concrete types into classes so those classes only need to know about the protocols, thereby keeping things cleanly decoupled.

```swift
class SomeController {

    private let a: ProtocolA
    private let b: ProtocolB
    private let c: ProtocolC

    init(a: ProtocolA = MyFactory.get(),
         b: ProtocolB = MyFactory.get(),
         c: ProtocolC = MyFactory.get()) {
        self.a = a
        self.b = b
        self.c = c
    }
}

```

This way only MyFactory knows what concrete types to return for the various protocols.

---

<div class="post-metadata">

**Author:** ![Gero](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gero/32/23571_2.png) [@Gero](https://forums.swift.org/u/Gero)\
**Post date:** [September 11, 2025, 8:53am UTC](https://forums.swift.org/t/switching-on-protocols/82002/9 "2025-09-11T08:53:31Z")

</div>

Be aware that with this you _may_ introduce some runtime overhead for performance. This mostly depends on how complex/large your concrete implementations for the protocols are, but the gist is that large-ish (memory footprint-wise) types result in an additional indirection, _even for value types conforming to the protocols_.

Let’s look at just one of the example properties you define here, `private let a: ProtocolA`. First off, I would recommend to spell this as `private let a: any ProtocolA`. This is the “more modern” Swift syntax I mentioned above and makes it, IMO, more explicit that you’re using an existential, i.e. a “box”. AFAIK, Swift implements this box in a way that small-ish concrete (value) types conforming to `ProtocolA` can be stored in it directly. This means when working with an instance during runtime, they’re pretty much as fast as using the (value) type directly. However, if it’s _too_ large, it may be moved to the heap and the box only contains a pointer to it. This may come as a surprise. Of course, if the concrete type is a reference type like a class, this makes no difference.

For your project that may make no difference, but especially if you’re providing this as a library for others, it might be difficult to gauge concrete runtime behavior/performance.

* * *

To alleviate this, you could also consider a different approach (though obviously I don’t know how well it fits your use-case): Generics.

By making `SomeController`generic over its properties’ types you can keep a level of decoupling, but shift more work to compile-time:

```swift
class SomeController<One: ProtocolA, Two, ProtocolB, Three: ProtocolC> {
    private let a: One
    private let b: Two
    private let c: Three
}

```

I cheated around the crux of this, obviously: The factory. Its `get` method then needs to specify a concrete type to make the default implementation work OR at least the place where you instantiate `SomeController`needs to specify the concrete types. To allow this to be more legible, you _may_ be able to use an opaque (return) type (like `some ProtocolA`, but I have found that often times this is not impossible.

In unit tests, for example, I use this all the time. SwiftUI is also a good example of how this works.

---

<div class="post-metadata">

**Author:** ![Gero](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gero/32/23571_2.png) [@Gero](https://forums.swift.org/u/Gero)\
**Post date:** [September 11, 2025, 3:03pm UTC](https://forums.swift.org/t/switching-on-protocols/82002/11 "2025-09-11T15:03:52Z")

</div>

Yes, this is an elegant way if you can determine the concretely needed type directly. In many cases you can, but since we don’t know what logic @stever’s factory type contains it might get a little messier or harder to design it in a way that determines the concrete type during compile time.

I’m a big fan of using opaque return types, but sometimes existentials are a good fit and more readable (e.g., if the concrete types are supposed to depend on a configuration file, they might be unavoidable).
