If a function with an opaque return typereturns from multiple places, all of the possible return values must have the same type. For a generic function, that return type can use the functionโs generic type parameters, but it must still be a single type. ๐Swift
the function body determines its concrete return type (including the concrete type of any associated type) at compile time. (๐็ฏไพ โญ๏ธ 5)
use PAT (protocol with associated types) as return types. (๐็ฏไพ โญ๏ธ 5)
preserve type identity (always return the same type). (๐็ฏไพ โญ๏ธ 2, 5)
the body of a SwiftUI view returns some View. (View is a PAT)
// protocolprotocolCanAdd {staticfunc+(a: Self, b: Self) -> Self}// protocol conformaning typesextensionInt:CanAdd {}extensionDouble:CanAdd {}extensionString:CanAdd {}// ---------------------------// โญ๏ธ generic function// ---------------------------// โญโโโโโโโโโโโโโโโ โญ๏ธ 1 โโโโโโโโโโโโโโฎfuncadd<T:CanAdd>(_a: T, _b: T) -> T {return a + b}// โญ๏ธ 1. generic function declaration// type parameters (i.e. T) determined by caller (call site)// caller (call site) determines type parameterslet r1 =add(42, 99)// T = Intlet r2 =add(3.1415, 1.618)// T = Doublelet r3 =add("Hello", "World")// T = String// -----------------------------// โญ๏ธ opaque return type// -----------------------------// protocolprotocolDescriber {funcdescribe() ->String}// conformaning typesstructHuman:Describer {funcdescribe() ->String { "Iโm a `Human`." }}structAnimal:Describer {funcdescribe() ->String { "Iโm a `Animal`." }}// โญโโโ โญ๏ธ 2 โโโโโฎfuncsomeDescriber() ->some Describer {Human()// concrete return type determined in here.}// โญ๏ธ 2. opaque return type// concrete return type determined by function bodyprint(type(of: someDescriber()))// โญ๏ธ (always) Human/* Opaque Return Type vs. Generic Type ----------------------------------- โข opaque return type: function BODY ("inside") determines its concrete return type. โข generic type: caller & type DECLARATION ("outside") determine its concrete type of type parameters.*/// -----------------------------// โญ๏ธ protocol type// -----------------------------// โญโ โญ๏ธ 3 โโฎfuncdescriber() -> Describer {Double.random(in:0..<1)>0.5?Human():Animal()}// โญ๏ธ 3. protocol type// can refer to MANY (conformaning) concrete types.print(type(of: describer()))// โญ๏ธ Human | Animal/* Opaque Type vs. Protocol Type ----------------------------- โข opaque type : always refers to ONE specific, concrete type. โข protocol type: can refer to MANY (conformaning) concrete types.*/// -----------------------------------------------// โญ๏ธ PAT (protocol with associated types)// -----------------------------------------------protocolHasData {associatedtype Data // associated typevar data: Data { get }}structIntData:HasData {var data: Int}structStringData:HasData {var data: String}// โญโโญ๏ธ 4โโฎ// func data() -> HasData {// StringData(data: "Yellow")// }// โ error: // protocol 'HasData' can only be used as a generic constraint // because it has Self or associated type requirements// โญ๏ธ 4. protocol type CANNOT determine its ASSOCIATED TYPE `Data`// from the function declaration ("outside").// โญโโ โญ๏ธ 5 โโโโฎfuncsomeData() ->some HasData {StringData(data:"Yellow")// return type is determined in here.// return type: StringData// associated type Data: String}// โญ๏ธ 5. opaque return type// let the BODY (implementation) of the function determine:// - concrete return type // - including concrete type of any associated type.print(type(of: someData()))// StringData
opaque return type:
its concrete type is determined by function body ("inside"). - ๐็ฏไพ โญ๏ธ 2, 5
generic type:
its placeholders (type parameters) & return type are determined by caller (call site) & type declaration ("outside"). - ๐็ฏไพ โญ๏ธ 1
Opaque Type vs. Protocol Type
opaque type :
always refers to ONE specific, concrete type. - ๐็ฏไพ โญ๏ธ 2, 5
protocol type:
can refer to MANY (conformaning) concrete types. - ๐็ฏไพ โญ๏ธ 3