Opaque Return Types in Swift

Tram Ho

Opaque Return Types is a new feature released in Swift 5.1 by Apple. It can be used to return some values ​​for method / function and property without property disclosing the type of value to the caller. The return type will be some of a protocol . Using this method, the module does not need to explicitly return the type and content of the method, it only needs to return the opaque type of a protocol with the keyword some . The Swift compiler can also retain the identity of return types unlike the use of protocol as return types. SwiftUI uses the opaque return type within it. View protocol will return some View in the body of the property.

Here are some essentials that opaque returns provide to keep in our toolbox and take advantage of whenever we want to create APIs with Swift:

  1. Provide a specific type of protocol without revealing the concrete type to the API caller for better encapsulation .
  2. Because the API does not expose a specific return type to the caller, the caller does not need to worry about if the underlying type is changed in the future as long as it implements the base protocol.
  3. Provides a strong guarantee of identity by returning a specific type at run time. The tradeoff is losing the flexibility of returning multiple types of recommended values ​​because using the protocol as a return type.
  4. Because the guarantee will return to a specific protocol. The function can return opaque protocol type if it has Self or requires associated type .
  5. The protocol leaves the decision about the type of return to the caller. And opaque is the opposite. It is the function determines the specific return type as long as it implements the protocol .

Take a look at an example of using Opaque return type.

To better understand opaque return type and why it is different from just using protocol as a return type.

Define a protocol with associatedtype

We have a protocol called MobileOS . This Protocol has an associatedtype called Version and a property to get Version for a specific type to implement.

Implement type specific to the protocol

Define two specific types for this protocol, called iOS and Android . Both have differences in the semantics of Version . iOS uses type float while Android uses String

Create a function to return a Protocol type

We want to return a function to return a MobileOS protocol as a return type. In the usual way we would write like this:

Solution 1 (Returns Protocol Type):

As you can see, the build failed because the protocol used associatedtype . The compiler does not retain the identity type of the return value when using the protocol as a return type. So now let’s try a few ways when returning a specific type.

Solution 2 (Returns Concrete Type):

This method seems to work. But you can see the caller can see the specific type. This code will probably need a lot of refactor times if in the future you want to change something like return Android as the function’s return type.

Solution 3 (Generic Function Return)

This approach seems more “professional”. But now the caller must provide a specific type for the function to return. But if you want the caller to really not care about the specific return type, then this method is not quite right.

Final Solution (Opaque Return Type to the rescue)

Using opaque return type, we can finally return MobileOS as a function’s return type. The compiler maintains the specific identity of the return type here and the caller doesn’t need to know the inner type of the return type as long as it implements the MobileOS protocol.

Opaque returns types can only return a specific type.

You might think that like the protocol return type, we can also return different specific types inside the opaque return type as follows:

The compiler will return an error if you try to return a different type for the opaque return value. You can only return different types of values ​​for the same specific type.

Simplify complexity and nested types into opaque return types

The final solution is an example of how to leverage the Opaque return type to hide complexity and nested types into a simple opaque protocol type that can be exposed to the caller.

Consider a function that accepts an array using common constraints for its element to comply with the numeric protocol. This array does a number of things:

  1. Get the first and last element of the array
  2. Lazily map function cleverly by performing its own operations for each element.

The caller of this function does not need to know the return type, the caller only needs to loop and print the value.

Try doing this using the function.

Solution 1: Using Generic Return Function

As you can see, the return type of this function is complex and nested LazyMapSequence<ArraySlice<T>, T> while the user uses it only to loop and print for each element.

Solution 2: Simple Opaque Return Types

Using this method, the user doesn’t need to know the return type of the function as long as it matches the sequence protocol the user uses.

Opaque Return Types in SwiftUI

SwiftUI also relies heavily on this approach, so the body in View doesn’t need to be explicit about the return type as long as the View protocol is followed. Otherwise, the return type inferred can be very nested and complex like this.

The return type of body would be:

It is quite complex and nested, remember that it will also change whenever we add a new nested view inside HStack. The Opaque return type really shines in SwiftUI implementations, users don’t really care about the specific type within the View long as the return type conforms to the View protocol.

The article about Opaque Return Type is over. Thank you for reading.

Source: https://medium.com/@alfianlosari/understanding-opaque-return-types-in-swift-9c36fb5dfa86

Share the news now

Source : Viblo