Functions vs Closures – a Beginner’s approach

1. Introduction

Computer programming is about solving problems and getting things done the right way. However, as a beginner, you don’t care how you do it as long as you get it done. It works so why bother tackling it in a completely different way after all?

I thought the same way when I first stumbled upon closures in Swift because they behave like functions. So I approached them reluctantly at first and soon asked myself how I lived without them.

The biggest challenge you face when discovering new programming paradigms is changing the way you think. This can be scary at first because you are used to doing things in a certain way and now you suddenly feel overwhelmed. It takes time and patience to get used to anything new but it’s worth doing it in the long run – being able to choose the right technique for a certain problem is a skill that any software developer should have in his toolbox.

OK, enough talking – let’s see what closures are all about.

2. The challenge

Your task for this tutorial is an easy one: convert a given number from base 2 to base 10. Before diving into coding, think how you would solve the problem and break it into steps. This is how I would do it:

  • create the number’s digits array and populate it with default values;
  • create the result variable and assign its initial value;
  • loop through the array and do three things for each iteration:
    • extract the current index and value from the array;
    • compute the digit’s power;
    • update the result with it;
  • print the result to the console;

That’s it for the algorithm – let’s move on to the implementation.

Note: You can read more about base conversion here.

3. The function implementation

Let’s create a helper function first that calculates the power of a certain base and exponent.

Fire up Xcode and open a playground. Delete everything from it and add the function’s prototype to kick things off:

func power(base: Int, exp: Int) -> Int {

}

The power function has two parameters – base and exp – of type Int and returns the base raised to the exponent power as an Int.

There are three things you should do inside the function’s body. First create the result variable and assign its initial value – it is variable because you are going to change its value soon:

var result = 1

Note: There are many different ways of creating variables in Swift – this is the easiest approach of all because it uses type inference to determine the variable’s type – Int in this case.

Next loop through the numbers between 0 and the exponent with the for in control flow statement and half open range operator:

for _ in 0..<exp {

}

Note: You use the underscore since you ignore the values of the sequence.

Note: You can read more about loops here.

There is only one thing you should do in the loop – update the result with the base value:

result *= base

Note: You can also do it like this – the initial approach is shorter because it uses the multiplication assignment operator:

result = result * base

Finally, return the result:

return result

Now let’s create the function that converts the number. Add the function’s signature to the playground:

func number(digits: [Int], base: Int) -> Int {

}

The number function has two parameters – the digits array of type [Int] and the base of type Int – and returns the converted number as an Int.

There are three things you should do inside the function’s body. First create the result variable and assign its initial value:

var result = 0

Next loop through the array with the for in statement:

for (rank, digit) in digits.enumerate() {

}

The enumerate method returns a tuple which contains the current index and value.

Note: You can read more about tuples here.

There is only one thing you should do inside the loop – update the result with the digit’s power:

result += digit * power(base, exp: digits.count - rank - 1)

Note: The power’s exponent goes from 0 to digits.count – 1, like the array’s indices – their sum is always constant and equal to digits.count – 1.

Note: You can also write it like this – the initial approach is shorter because it uses the addition assignment operator:

result  = result + digit * power(base, exp: digits.count - rank - 1)

Note: There are many ways of looping in Swift – this is the best approach in this case because it gives you access to the index and value for each iteration.

Finally, return the result:

return result

Now create the number’s digits constant array and assign its initial values:

let digits = [1, 0, 0, 1]

The digits of a certain base go from zero to the base number minus one.

Then convert the number – use 2 for the function’s base argument to be consistent with the array’s values:

number(digits, base: 2)

Note: Feel free to use any other value for the base parameter – make sure to modify the digits array’s values accordingly.

4. The closure implementation

The previous implementation uses a helper function – that’s a good approach, but you can do better with closures.

Closures are anonymous functions – they don’t have a name. They behave like first class citizens – you can assign them to variables or even use them as arguments for other functions.

Add this line to the playground to kick things off:

let cpower = {(base: Int, exp: Int) -> Int in

}

Here you create a closure that has the same prototype as the power function you used earlier and assign it to a constant.

Note: The in keyword separates the closure’s signature and body.

The closure’s body matches the function’s one, so go ahead and add it between the closure’s brackets:

var result = 1
    
for _ in 0..<exp {
        
   result *= base
        
}

return result

Next create a new conversion function by adding a closure parameter to the initial one you previously defined:

func cnumber(digits: [Int], base: Int, closure: (base: Int, exp: Int) -> Int) -> Int {

}

Now modify the function’s implementation so that it uses the closure argument instead of the power function:

var result = 0
    
for (rank, digit) in digits.enumerate() {
        
  result += digit * closure(base: base, exp: digits.count - rank - 1)
        
}
    
return result

Finally, convert the number:

cnumber(digits, base: 2, closure: cpower)

That’s great, but you can do even better by combining the closure’s signature and implementation and getting rid of the intermediate constant, so let’s do just that!

5. The closure implementation revisited

Add the power closure’s body to the conversion function’s closure parameter declared in the previous section and assign the function call to a constant:

let value = cnumber(digits, base: 2, closure: {(base: Int, exp: Int) -> Int in
    
    var result = 1
    
    for _ in 0..<exp {
        
        result *= base
        
    }
    
    return result

})

Finally, print the number to the console:

print(value, terminator: "")

Note: There are other ways to print to the console as well – this approach doesn’t print the newline “\n” character in the playground.

Note: There are many other ways of defining the closure – this is the easiest approach of all, since it uses trailing closure syntax.

6. Functions vs closures comparison

Functions advantages:

  • clear steps
  • easy to understand

Functions disadvantages:

  • boilerplate code

Closure advantages:

  • no boilerplate code
  • short and sweet

Closure disadvantages:

  • difficult to understand

7. Conclusion

Both paradigms have their pros and cons – feel free to try them both and choose the one that suits you best. Happy coding! 🙂

Note: All the code in this tutorial was tested with a playground in Xcode 7.2 and Swift 2.1 (Download).

Advertisements
Posted in Swift

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Enter your email address to receive notifications of new posts by email.

Simple Programmer
%d bloggers like this: