Shorthand syntax for closures

In this section, we will look at a couple of ways to shorten the definition of closures.

Using the shorthand syntax for closures is really a matter of personal preference. There are a lot of developers that like to make their code as small and compact as possible, and they take great pride in doing so. However, at times this can make code hard to read and understand for other developers.

The first shorthand syntax for closures that we are going to look at is one of the most popular, and is the syntax we saw when we were using algorithms with arrays in Chapter 3, Using Swift Collections and the Tuple Type. This format is mainly used when we want to send a really small (usually one line) closure to a function, like we did with the algorithms for arrays. Before we look at this shorthand syntax, we need to write a function that will accept a closure as a parameter:

func testFunction(num: Int, handler:() -> Void) {
for _ in 0..<num { handler() } }

This function accepts two parameters--the first parameter is an integer named num, and the second parameter is a closure named handler that does not have any parameters and does not return any value. Within the function, we create a for loop that will use the num integer to define how many times it loops. Within the for loop, we call the handler closure that was passed into the function.

Now let's create a closure and pass it to the testFunction() as follows:

let clos = { 
  () -> Void in 
  print("Hello from standard syntax") 
} 
testFunction(num: 5, handler: clos) 

This code is very easy to read and understand; however, it does take five lines of code. Now let's look at how to shorten this code by writing the closure inline within the function call:

testFunction(num: 5,handler: {print("Hello from Shorthand closure")}) 

In this example, we created the closure inline within the function call, using the same syntax that we used with the algorithms for arrays. The closure is placed in between two curly brackets ({}), which means the code to create the closure is {print("Hello from Shorthand closure")}. When this code is executed, it will print out the message Hello from Shorthand closure five times on the screen.

The ideal way to call the testFunction() with a closure, for both compactness and readability, would be as follows:

testFunction(num: 5) {  
  print("Hello from Shorthand closure") 
} 

Having the closure as the final parameter allows us to leave off the label when calling the function. This example gives us both compact and readable code.

In Chapter 3, Using Swift Collections and the Tuple Type, we saw that we were able to pass parameters to the array algorithms using the $0, $1, $2, and so on, parameters. Let's look at how to use parameters with this shorthand syntax. We will begin by creating a new function that will accept a closure with a single parameter. We will name this function testFunction2. The following example shows what the new testFunction2 function does:

func testFunction2(num: Int, handler: (_ : String)->Void) {
for _ in 0..<num { handler("Me") } }

In testFunction2, we define the closure like this: (_ : String)->Void. This definition means that the closure accepts one parameter and does not return any value. Now let's look at how to use the same shorthand syntax to call this function:

testFunction2(num: 5){ 
  print("Hello from ($0)") 
} 

The difference between this closure definition and the previous one is $0. The $0 parameter is shorthand for the first parameter passed into the function. If we execute this code, it prints out the message Hello from Me five times.

Using the dollar sign ($) followed by a number with inline closures allows us to define the closure without having to create a parameter list in the definition. The number after the dollar sign defines the position of the parameter in the parameter list. Let's examine this format a bit more, because we are not limited to only using the dollar sign ($) and number shorthand format with inline closures. This shorthand syntax can also be used to shorten the closure definition by allowing us to leave the parameter names off. The following example demonstrates this:

let clos5: (String, String) -> Void = {  
  print("($0) ($1)") 
} 

In this example, the closure has two string parameters defined; however, we do not give them names. The parameters are defined like this: (String, String). We can then access the parameters within the body of the closure using $0 and $1. Also, note that the closure definition is after the colon (:), using the same syntax that we use to define a variable type rather than inside the curly brackets. When we use anonymous arguments, this is how we would define the closure. It will not be valid to define the closure as follows:

let clos5b = { 
  (String, String) in  
  print("($0) ($1)") 
} 

In this example, we will receive an error letting us know that this format is not valid. Next, let's look at how we would use the clos5 closure as follows:

clos5("Hello", "Kara") 

Since Hello is the first string in the parameter list, it is accessed with $0, and as Kara is the second string in the parameter list, it is accessed with $1. When we execute this code, we will see the message Hello Kara printed to the console.

This next example is used when the closure doesn't return any value. Rather than defining the return type as Void, we can use parentheses, as the following example shows:

let clos6: () -> () = {  
  print("Howdy") 
} 

In this example, we define the closure as () -> (). This tells Swift that the closure does not accept any parameters and also does not return a value. We will execute this closure as follows:

clos6() 

As a personal preference, I am not very fond of this shorthand syntax. I think the code is much easier to read when the void keyword is used rather than the parentheses.

We have one more shorthand closure example to demonstrate before we begin showing some really useful examples of closures. In this last example, we will demonstrate how we can return a value from the closure without the need to include the return keyword.

If the entire closure body consists of only a single statement, then we can omit the return keyword, and the results of the statement will be returned. Let's look at an example of this:

let clos7 = {(first: Int, second: Int) -> Int in first + second } 

In this example, the closure accepts two parameters of the integer type and will return an instance of the integer type. The only statement within the body of the closure adds the first parameter to the second parameter. However, if you notice, we do not include the return keyword before the additional statement. Swift will see that this is a single statement closure and will automatically return the results, just as if we put the return keyword before the addition statement. We do need to make sure the result type of our statement matches the return type of the closure.

All of the examples shown in the previous two sections were designed to show how to define and use closures. On their own, these examples did not really show off the power of closures and they did not show how incredibly useful closures are. The remainder of this chapter is written to demonstrate the power and usefulness of closures in Swift.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset