Once we have defined the operator, we can write top-level functions that implement the behavior for each pair of types: one on the left-hand side (LHS) and one on the right-hand side (RHS). Method parameter overloading allows us to specify the operator implementation for multiple-type pairings.
We can also implement it for our own custom types. Let's create Task and TaskList, which might benefit from using the operator:
struct Task {
let name: String
}
class TaskList: CustomStringConvertible {
private var tasks: [Task] = []
func append(task: Task) {
tasks.append(task)
}
var description: String {
return tasks.map { $0.name }.joined(separator: "\n")
}
}
We'll add CustomStringConvertible conformance so that we can easily print out the result.
An alternative to implementing the use of an operator as a top-level function is to declare it within the relevant type as a static function. We'll declare it within an extension on our TaskList object, but we can just as easily declare it within the main TaskList class declaration:
extension TaskList {
static func >>> (lhs: Task, rhs: TaskList) {
rhs.append(task: lhs)
}
}
Implementing this within a type has a few advantages: The implementation code is right next to the type itself, making it easier to find, and taking advantage of any values or types that might have a private, or otherwise restricted, access control, which will prevent them from being visible to a top-level function.
Now we can use our >>> operator to append Task to a TaskList:
let shoppingList = TaskList()
print(shoppingList)
Task(name: "get milk") >>> shoppingList
print(shoppingList)
Task(name: "get teabags") >>> shoppingList
print(shoppingList)