Skip to main content
Version: Next

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.


_41
access(all) struct interface HasID {
_41
access(all) let id: String
_41
}
_41
_41
access(all) struct A: HasID {
_41
access(all) let id: String
_41
_41
init(id: String) {
_41
self.id = id
_41
}
_41
}
_41
_41
access(all) struct B: HasID {
_41
access(all) let id: String
_41
_41
init(id: String) {
_41
self.id = id
_41
}
_41
}
_41
_41
// Create two instances, one of type `A`, and one of type `B`.
_41
// Both types conform to interface `HasID`, so the structs can be assigned
_41
// to variables with type `{HasID}`: Some resource type which only allows
_41
// access to the functionality of resource interface `HasID`
_41
_41
let hasID1: {HasID} = A(id: "1")
_41
let hasID2: {HasID} = B(id: "2")
_41
_41
// Declare a function named `getID` which has one parameter with type `{HasID}`.
_41
// The type `{HasID}` is a short-hand for `AnyStruct{HasID}`:
_41
// Some structure which only allows access to the functionality of interface `HasID`.
_41
//
_41
access(all) fun getID(_ value: {HasID}): String {
_41
return value.id
_41
}
_41
_41
let id1 = getID(hasID1)
_41
// `id1` is "1"
_41
_41
let id2 = getID(hasID2)
_41
// `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:


_22
access(all) struct interface HasMetadata {
_22
access(all) let metadata: AnyStruct
_22
}
_22
_22
access(all) struct C: HasID, HasMetadata {
_22
access(all) let id: String
_22
access(all) var metadata: AnyStruct
_22
_22
init(id: String) {
_22
self.id = id
_22
}
_22
_22
fun setMetadata(_ data: AnyStruct) {
_22
self.metadata = data
_22
}
_22
}
_22
_22
// valid, because `C` implements both `HasID` and `HasMetadata`.
_22
let hasID3: {HasID, HasMetadata} = C(id: "3")
_22
_22
// valid, because `A` implements only `HasID`.
_22
let hasID4: {HasID, HasMetadata} = A(id: "4")