Function decorators

Assign functions to variables

func greeting(firstName: String, lastName: String) -> String { return "Hello, " + firstName + " " + lastName + "!" } let greetSomeone = greeting println(greetSomeone("John", "Doe")) // => Hello, John Doe!

Functions can be passed as parameters to other functions

func johnDoeFunction(function: (String, String) -> String) -> String { return function("John", "Doe") } println(johnDoeFunction(greeting)) // => Hello, John Doe!

Functions can return other functions

func composeHelloFunction() -> (String -> String) { func hello(name: String) -> String { return "Hello, " + name } return hello } let helloFunc = composeHelloFunction() println(helloFunc("John")) // => Hello, John

func hello(name: String) -> String { return "Hello, " + name } func bold(function: String -> String) -> (String -> String) { func decoratedBold(text: String) -> String { return "" + function(text) + "" } return decoratedBold } let boldHello = bold(hello) println(boldHello("Vladimir")) // => Hello, Vladimir

func bold(function: String -> String)

String

String

Abstract Functor

class F<T1, T2> { let f: T1 -> T2 init(function: T1 -> T2) { self.f = function } func run(args: T1) -> T2 { return f(args) } }

func logger(text: String) { println("LOG: \(text)") } let loggerFunc = F(logger) loggerFunc.run("Hello") // => LOG: Hello

func bold(function: F<T1, String>) -> F<T1, String> { func decoratedBold(args: T1) -> String { return "" + function.run(args) + "" } return F(decoratedBold) } let boldGreeting = bold(F(greeting)) println(boldGreeting.run("John", "Doe")) // => Hello, John Doe! let boldHello = bold(F(hello)) println(boldHello.run("Vladimir")) // => Hello, Vladimir

Composing functions

+

func +<T1, T2>(beforeHook: F<(), ()>, function: F<T1, T2>) -> (T1 -> T2) { func composedFunc(args: T1) -> T2 { beforeHook.run() return function.run(args) } return composedFunc } func +<T1, T2>(function: F<T1, T2>, afterHook: F<T2, ()>) -> (T1 -> T2) { func composedFunc(args: T1) -> T2 { var result = function.run(args) afterHook.run(result) return result } return composedFunc }

+

Void -> Void

T2 -> Void

func logger(text: String) { println("LOG: \(text)") } func request(url: String) -> String { return "Success 200" } let logRequest = F(request) + F(logger) logRequest("http://some.awesome.url") // => "LOG: Success 200" let composedRequest = F({ println("Request is fired!") }) + F(request) println(composedRequest("http://some.awesome.url")) // => Request is fired! // => Success 200

+

Before

After

let composedRequest = Before(request).run({ println("Request is fired!") }) let loggedRequest = After(request).run(logger)

Retry/repeat function call

class F<T1, T2> { ... func repeat(args: T1, times: Int) -> T2 { for i in 1..times { f(args) } return f(args) } func retry(args: T1, maxTries: Int, condition: () -> Bool) -> T2 { var tries = 0 var result: T2? while !condition() && tries < maxTries { result = f(args) tries++ } return result! } }

func greeting(firstName: String, lastName: String) { print("Hello, " + firstName + " " + lastName + "!") } F(greeting).repeat(("John", "Doe"), times: 3) // => Hello, John Doe! Hello, John Doe! Hello, John Doe!

var requestResult: Int = 0 func randomRequest(url: String) { let result = Int(arc4random_uniform(UInt32(2))) if result > 0 { requestResult = 200 } else { requestResult = 404 } } F(randomRequest).retry("http://some.awesome.url", maxTries: 5, condition: { requestResult == 200 })

Conclusion

In Swift – the new programming language introduced by Apple – functions are first class citizens. This basically means, that a function can be passed as a parameter, returned from another function or assigned to a value. It allows us to do a lot of useful stuff with them.Let’s use the concepts of function as a first class citizen to implement some basic function decorator.This concept allows us to implement function decorators in Swift.Function decorators work as wrappers to existing functions, modifying the behavior of the code before and after a target function, without the need to modify the function itself. They augment the original functionality, thus decorate it.Using the concepts above let’s write a simple decorator that wraps the String output of another function by some html tag.We wrote a function that takes another function as an argument, generates a new function, augmenting the work of the original function, and returns the generated function so we can use it anywhere. Decorating function also allows us to insert some behaviour before/after function call or combine multiple functions into one.In the example above we had to explicitly specify the signature of the function to decorate:. We’ve implemented bold decorator so that it decorates a function from onevalue, which returns anothervalue. But what if one would like to create bold decorator which accepts functions with different signatures?Let’s define an abstract Functor class. By ‘Functor’ let’s assume a class, which wraps any function and allows to call that function.This class allows us to wrap any function and call it somewhere:Using the Functor class we can now rewrite bold decorator to accept functions with different number of parameters:Another interesting approach of using function decorators is composing several functions into single one.Swift allows overloading basic operators. Let’s try to overloadoperator to accept two functions and compose them into one function.Above you can see two overloads ofoperator which accept functors of different types and combine them into a single function. The first overloaded version runs afunction before main function, and the second one runs main function, then passes its result to anotherfunction and returns the result of the main function.Let’s write an example of using this approach:We could also implementoperator overload for plain functions, not for Functor type, but overloading operators for basic types may be a bad practice.Another approach of composing functions may be implemented with some helper classes and without overloading operators. As an example of doing this take a look atandclasses here . They allow us to compose functions in another way:One another way of using function decorators and Functor class, implemented above, is to write Repeat and Retry decorators. It will allow to run a single function multiple times or until some condition is met.Code above allows us to implement multiple calling of a function mechanism like this:Or we can run a function until some condition is met or until we have performed some number of tries:This article demonstrates a basic approach of decorating and composing functions in Swift. It is pretty easy to implement Decorator pattern in Swift and many useful decorators may be implemented using the described approach.Having functions as first class citizens may allow creating clean, short and extensible code, which will be pretty easy to understand.All the code examples for this article could be found in this repository