Opaque Return type

Nitesh Kumar Pal
Globant
Published in
5 min readJun 22, 2020
Opaque return type is reverse generic behaviour. What?

Well, How does generic behave? 🤔

Generic function, class, structure, enum, or associatedtype are designed with such an abstract and general manner that their caller decides what type should be bound as the type of generic type’s placeholders and Generic code would work for all the types. For example:

Here at the time of calling printArray function whatever type is passed, Int and String for example in this code snippet are passed, They become deciding type for the caller. printArray method would work for all types because of its generic behaviour. For more details on generic please check Generic type in Swift.

Reverse Generic

Let’s just reverse the statement used for explaining the Generic above. Reverse generic means when return type or parameter type is decided inside its hosted code (like inside class, struct, enum, or function itself).

Opaque return type (ORT)

ORT implies when the caller doesn’t need to specify the underlying return type or parameter type and the caller must get concrete type for sure.

Let’s see different types of use cases, By which we can solve the problems with the help of Opaque return type:

UseCase 1: Self or associated type requirements 👇

Though Mobile confirms the protocol UniqueProduct, you cannot set UniqueProduct as return type because of its generic behaviour, It requires special treatment. Let’s see how we can resolve the issue 👇

Solution 1:

We can directly return the concrete type Mobile as per reverse Generic concept says that the caller must get concrete type.

Check the type by option + click on product, we can see manufactureProduct() is returning Mobile so as due to type inference product type is set as Mobile.

But we have a problem here, If we set Mobile as return type, it will expose the return type to the caller it means doesn’t completely comply ORT. Let's see how to resolve this issue in Solution 2.

Solution 2:

Opaque return type comes to rescue from exposing the return type to the caller.

(some is the keyword to indicate ORT)
Check the type by option + click on product, we can see manufactureProduct() is now showing some UnqueProduct as return type.

Here some UniqueProduct implies that manufactureProduct() will return a concrete type which must confirm UniqueProduct protocol. This exactly what reverse generic concept is.

The caller would not know the type of product whether it’s Mobile or Tablet. Here we are taking benefit of ORT which defined the return type as ORT by using some keyword.

Phew! now you must have digested Reverse Generic with ORT, let's check UseCase 2 next

UseCase 2: Hiding the complex return type by using the ORT 👇

Please check this code sample before further reading.

In the above code snippet, same code is written in two functions getShortListedStudentList and getShortListedStudents.

The code written in function getShortListedStudentList is actually returning the type LazyMapSequence<LazyFilterSequence<LazySequence<[Student]>.Elements>, String>
so as the type of shortListedBySixtyCutOff constant would be the same due to type inference. With the help of ORT, we can hide these unnecessary type details.

The caller is much interested to get the result type only, which is simply Collection type here as per the requirement. so just by setting some Collection as return type of getShortListedStudents solves the issue of exposing all type details to shortListedBySeventyCutOff constant.

We can see the same approach is used for View protocol in SwiftUI

Option + click on stack
It’s returning the complex type as VStack<TupleView<(Text, Text)>> but the type of body would be always some View which implies that it would always carry a concrete type with the abstraction of ORT

UseCase 3: You cannot cheat with ORT for its concrete type.

With ORT as return type, You cannot write such code that can potentially return more than one type if you do compiler won’t let you 😈.

Let’s see what it means:

Either return type can be Mobile
or return type can be Tablet
But function cannot return multiple types if the return type is OTR.

Summary

  • The use of Opaque return type is very specific as you can see in Usecase1 (Self or associated type requirements in Protocol) and Usecase2 (Hiding the complex return type by using the ORT).

struct VStack<Content> : View where Content : View

In SwiftUI, Observe such types like HStack, ZStack, Group, List, etc, they confirm View and also expect their generic type (Content) whatever it would be must confirm View.

  • There are many such generic types in SwiftUI which can enclose other views that create a complex structure of type. ORT is very helpful to the client (caller) who will only know that this structure is some View.
  • ORT makes your code more performant at runtime. Since protocols force compiler to check its underlying concrete type at runtime which imposes overhead on performance. but ORT gives surety of the concrete type to the compiler even at compile time.
  • Generally in Application development, since we don't deal much with generics and Self or associatedtype in the protocol, I personally find very fewer reasons to use ORT, but on the other hand, If you are building the framework or library where you are going to use ORT use cases (1,2 and 3) extensively and you want to make your code flexible, highly reusable and with the abstraction of complex Generic types to the caller, you should use ORT.
  • We need flexibility sometimes as a developer by returning more than one concrete type from a function based on certain value (different cases of enum let’s say) of parameter, at such places we cannot use ORT.

You can check more details about Opaque type in following links:
Swift-Book: Opaque Type
Proposal for Opaque return type: SE-0244

Thank you for reading the blog, let me know if more use-cases you find, we can add them here too. Share your thoughts on it.

--

--