Dev.to · 6 min read

Swift Protocols — Opaque Return Types and the Mystery of `some` 🔮

Swift Protocols — Opaque Return Types and the Mystery of `some` 🔮

You've seen some View in every SwiftUI file you've ever opened. Now let's find out what it actually means, why it exists, and why returning a plain protocol doesn't work the same way. Fair warning: this topic is genuinely one of the more brain-bendy things in Swift. I'm going to tell you upfront that you don't need to fully understand the internals to keep going — but you do need to know it exists and roughly what it's doing, because you've already been using it every single time you've written a SwiftUI view. That some View in every SwiftUI file? That's an opaque return type. And now we're going to actually understand what that means. 🍥 Let's Start With Something That Works Two simple functions: func getRandomJutsu() -> Int { Int.random(in: 1...100) } func getRandomSuccess() -> Bool { Bool.random() } Both Int and Bool conform to a protocol called Equatable — which means they can be compared using ==. So you can do this: print(getRandomJutsu() == getRandomJutsu()) That works fine, comparing two random integers. Now, since both return types conform to Equatable, you might think: what if we simplify both functions to return Equatable instead of their specific types? The Thing That Doesn't Work func getRandomJutsu() -> Equatable { // ❌ Int.random(in: 1...100) } func getRandomSuccess() -> Equatable { // ❌ Bool.random() } Swift refuses this with an error message so confusing it might as well be written in ancient runes: "protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements." Here's the actual problem in plain English: if both functions return Equatable, Swift loses track of what specific type is coming back. And if it doesn't know the specific type, it can't know whether two Equatable things can actually be compared to each other. Think about it: an Int and a Bool both conform to Equatable, but you can't compare them with ==. That doesn't make sense. Swift isn't going to let you write code that might try to compare a jutsu power level to a true/false value just because they technically both conform to the same protocol. Why Returning a Protocol Can Work (In Other Cases) Returning a protocol isn't always wrong — it's actually really useful in the right situation. Remember the Fighter protocol from the last article? If you have a function that might return a Ninja or a Samurai depending on conditions, returning Fighter is perfectly valid: func chooseFighter(needsSpeed: Bool) -> Fighter { if needsSpeed { return Ninja() } else { return Samurai() } } This works because Ninja and Samurai are genuinely interchangeable when it comes to Fighter functionality. If you call chooseFighter() you get back some fighter, and you can call estimateTravelTime() and travel() on whatever comes back, and it'll work. But Equatable is different. Two Equatable things might not be compatible with each other at all — and == requires them to be the same type. Returning Equatable hides too much information. Swift can't do its job with that little to go on. Enter Opaque Return Types: the some Keyword The fix is adding some before the return type: func getRandomJutsu() -> some Equatable { Int.random(in: 1...100) } func getRandomSuccess() -> some Equatable { Bool.random() } Now both functions compile. And now this works: print(getRandomJutsu() == getRandomJutsu()) So what did some actually change? Without some: returning Equatable means "some Equatable thing — could be anything, we're not saying." Swift loses track of what's actually in there. With some: returning some Equatable means "a specific Equatable type — we're just not telling you which one." Swift knows exactly what type is coming back behind the scenes. It just doesn't expose that information to the outside world. The difference is subtle but crucial: some hides the type from you, not from Swift. The compiler always knows the real concrete type. It just doesn't make you write it out. A Tale of Two Phrases Here's the cleanest way I've found to hold this distinction: "Any Vehicle" — some kind of vehicle, could be any of several types, we genuinely don't know which "Some Vehicle" — a specific kind of vehicle, we know exactly which one internally, we just choose not to say Returning a protocol directly is the "any" version. Swift doesn't know which type it'll get, so it can't make guarantees about what's actually possible with it. Returning some Protocol is the "some" version. Swift tracks the real type internally, which means it can guarantee everything will work correctly — you're just not required to spell out the full type name. Why This Matters Enormously in SwiftUI Okay. Deep breath. Here's where it all comes together. Every time you write a SwiftUI view, you're returning something from the body property: var body: some View { VStack { Text("Naruto") Image("naruto-portrait") Button("Activate Jutsu") { } } } What's the actual return type of that body? It's not just View. It's some deeply nested SwiftUI type that describes the exact layout you built — a VStack containing a Text and an Image and a Button with specific configurations. The full type is legitimately enormous. It would be a mile long if you had to write it out. And every time you change your layout — add a spacer, change a color, add a new element — the type changes too. Without some View, you'd have to write that entire type out explicitly as the return type of body. And then update it every time you changed anything. That would be an absolute nightmare. With some View, you just say: "this body returns some kind of view, Swift — you figure out exactly what kind." Swift does exactly that, tracks the real type internally, and everybody is happy. The One Thing To Hold Onto some means "a specific type that I know but won't tell you." The compiler always knows what's really there — you're just not required to write it out. That's why some View works in SwiftUI. Swift knows the exact type of your entire view layout. You just don't have to write out the monstrous type signature every time you add a button. 🌸 This article was written by me; AI was used to improve grammar and readability.

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News