An example of the “Trust Me” operator

Let me explain: I write a lot of Swift.

At work I write Swift (and some Objective-C but I would rather not talk about it). In most of my side projects I write Swift. Whenever I need a quick script I write it in Swift.

Disclaimer

Some code snippets make use of unconventional symbols or unusual syntax. Use at your own discretion. Sharing code with teammates who might not be familiar with such syntax might hurt more that it helps.

Declaring Custom Operators

Operators are the root of all evil and must be avoided at all cost. That’s the conventional wisdom of anyone who worked with an operator heavy library in Scala or in C++.

But there is a class of operators that I think have their place in the world. Indeed, operators which handle generic types with no ambiguity, or which express intent more clearly than typical Swift syntax have a real value. They allow the user to understand what the code does rather than how to manipulate the syntax in order to make the code work.

For example I argue that:

A + B * C ^ D

is more readable than

add(A, times(B, power(C, D)))

Moreover, since many languages have some sort of infix and prefix operator syntax, operators help with familiarity by being language agnostic.

Here is a couple of operators that I often define in my personal projects.

Negation operator

If you’re familiar with DeMorgan laws you probably saw it written like this

One of the DeMorgan Law

Well turns out this

¬(a && b) == ¬a || ¬b

is valid Swift syntax (and will always evaluate to true).

This cute syntax is allowed by Swift custom operators, here is the declaration

Of course this shorthand for “!” only makes sense if you’re mathematically inclined.

You can make the “¬” symbol on macOS with alt-L on US keyboard layout.

Composition operator

Have you heard of point free notation? It’s when you do this:

let h = f • g

Which is equivalent to this

let h = { x in f(g(x)) }

or this

let h = {f(g($0))}

But none of those expressions are particularly pleasant to read. In both cases we introduce unnecessary brackets, and have to decipher nested parentheses.

Of course point free notation is not free of “points” in it’s syntax, but it’s free of declaring an intermediate closure with superfluous argument names.

Point free notation is quite rare in Swift because • is not an operator in the standard library, but when you start using it it’s hard to stop. For example:

let saveOnDisk = store • serialize

Conveys clearly that the function which saves your data on disk serializes the data in a representable way for your data storage and then stores the result on disk.

If we write the types down we have

func serialize(data: Data) -> JSON { … }

func store(json: JSON) -> () { … }

let saveOnDisk: (JSON) -> () = store • serialize

You can also use point free notation in your tests:

func testSerialize() {

let data = …

let doNothing = deserialize • serialize

XCTAssert(data, doNothing(data))

}

which tests that doNothing is, in fact, an identity function.

You can find the “•” operator on your keyboard by typing alt-8 on macOS using US layout.

As for the implementation, here is one, but I would suggest you import either Swiftz or Swiftx.

Partial Application Operators

When you write a lot of something, you start to see patterns emerging. Here is one:

You have an app which lists all orders for a given customer. Orders are represented with their state

enum CustomerOrder {

case shipped(Int)

case awaitingPayment

}

Assuming you have a list of orders: [CustomerOrder] you want all the orders which need payment. Of course you can write it like so:

orders.filter { $0 == .awaitingPayment}

but after a while you start questionning why do you even type those brackets and this $0 argument. Turns out this is valid

orders.filter(==.awaitingPayment)

It uses == as a prefix operator

And you can do the same with comparison operators. Unfortunately, some operators cannot be overriden (postfix > and prefix < ) so we are stuck with using combinations of <? and things like that as a workaround.

let ages: [Int] = users.map {$0.age}

let allCanDrink = ages.forAll(suchThat: ?>21) let allAreBabies = ages.forAll(suchThat: ?<4)

and you can do the same with with postfix arguments

let wontEnjoyRetiring = ages.forAll(suchThat: 40>?)

And here is the detailed implementation:

https://gist.github.com/andrevidela/45c734248a3cb0a0507123c89df08699

Array Exension

You probably noticed that the forAll(suchThat:) method does not exist in the standard library. But thanks to extensions we can easily define it for arrays:

extension Array {

func forAll(suchThat predicate: (Element) -> Bool) -> Bool {

return ¬self.contains(where: {¬predicate($0)})

}

}

And many more!

There are many other helper functions, extensions and types that we all regularly define and use. I would greatly appreciate if you shoot me an email or send a tweet with your favorite custom declaration that helps you reduce boilerplate and express your intent clearly.