To celebrate the launch of V2 of my blog, I'm starting a new series. This series will be called Nifty<Swift>. It highlights some of the quirky and nifty things you can do with the Swift language. I haven't yet determined the frequency I will be posting these, so the best way to get notified will likely be via Twitter.

First off, I found out about this feature after this reply from @TheMartianLife, so thank you Mars!

A reply from Mars to a tweet asking what people wish they knew when they started learning Swift.

So, without further ado, let's jump into it:

The actual Swift proposal is here, and is titled "Callable values of user-defined nominal types". It appears to build on top of some older proposals, but I'll go over what those are in another post.

View the original swift-evolution proposal here.


What are callable values?

Well, Callable values allow you to call objects like a function. For instance (using the examples provided by the proposal), you may have a polynomial object. You could initialize this object with some coefficients, and then later on call that object like a function, plugging a value for x.

What's so great about them?

Callable values are great syntactically, as it makes it much nicer to use than having a function (syntactically) that you need to call on the object.

For instance, it's much nicer to write MyPolynomial(3)  than it is to write MyPolynomial.evaluated(at: 3)

How can I use them?

Glad you asked (did you, really?). To use callable values,  you create a method with the identifier callAsFunction. That's it! Super simple.

Check out the below example, where I write a distance calculator (useful for calculating distance travelled when drivers are distracted and going certain speeds).

In the example below, I make use of Swift Measurement objects. The user specify's speed using a UnitSpeed object, and the distance travelled is then returned via the callAsFunction method.

In the below example, 'metres' has the value 27.7778, which is 27.7778 metres per second, and is returned as a Measurement<UnitLength>.

// James Dale

import Foundation

struct DistanceCalculator {
    let speed: Measurement<UnitSpeed>
}

extension DistanceCalculator {
    
    /// Callable
    /// - Parameter time: The time in seconds
    /// - Returns: The distance travelled, in metres
    func callAsFunction(_ time: TimeInterval) -> Measurement<UnitLength> {
        let metresPerSecond = speed.converted(to: .metersPerSecond)
        return Measurement<UnitLength>(value: metresPerSecond.value * time, unit: .meters)
    }
    
}

let car = DistanceCalculator(speed: .init(value: 50, unit: .kilometersPerHour))
let metres = car(2)