Intersection Types
Interface types cannot be used in type annotations directly; instead they must be used as part of intersection types. An intersection type represents a value that conforms to all of the interfaces listed in the intersection.
The syntax of a intersection type is {U1, U2, ... Un}
,
where the types U1
to Un
are the interfaces that the type conforms to.
The members and functions of any of the set of interfaces are available.
Intersection types are useful for writing functions that work on a variety of different inputs. For example, by using an intersection type for a parameter's type, the function may accept any concrete value that implements all the interfaces in that intersection. The value is restricted to the functionality of the intersection; if the function accidentally attempts to access other functionality, this is prevented by the static checker.
_50access(all)_50struct interface HasID {_50 access(all)_50 let id: String_50}_50_50access(all)_50struct A: HasID {_50_50 access(all)_50 let id: String_50_50 init(id: String) {_50 self.id = id_50 }_50}_50_50access(all)_50struct B: HasID {_50_50 access(all)_50 let id: String_50_50 init(id: String) {_50 self.id = id_50 }_50}_50_50// Create two instances, one of type `A`, and one of type `B`._50// Both types conform to interface `HasID`, so the structs can be assigned_50// to variables with type `{HasID}`: Some resource type which only allows_50// access to the functionality of resource interface `HasID`_50_50let hasID1: {HasID} = A(id: "1")_50let hasID2: {HasID} = B(id: "2")_50_50// Declare a function named `getID` which has one parameter with type `{HasID}`._50// The type `{HasID}` is a short-hand for `AnyStruct{HasID}`:_50// Some structure which only allows access to the functionality of interface `HasID`._50//_50access(all)_50fun getID(_ value: {HasID}): String {_50 return value.id_50}_50_50let id1 = getID(hasID1)_50// `id1` is "1"_50_50let id2 = getID(hasID2)_50// `id2` is "2"
If more than two interfaces are present in an intersection type, any concrete value of that type must implement both of them:
_31access(all)_31struct interface HasMetadata {_31 access(all)_31 var metadata: AnyStruct_31}_31_31access(all)_31struct C: HasID, HasMetadata {_31_31 access(all)_31 let id: String_31 _31 access(all)_31 var metadata: AnyStruct_31_31 init(id: String) {_31 self.id = id_31 self.metadata = []_31 }_31_31 access(all)_31 fun setMetadata(_ data: AnyStruct) {_31 self.metadata = data_31 }_31}_31_31// valid, because `C` implements both `HasID` and `HasMetadata`._31let hasID3: {HasID, HasMetadata} = C(id: "3")_31_31// Invalid, because `A` implements only `HasID`._31let hasID4: {HasID, HasMetadata} = A(id: "4")