Apple Reference, Articles, and Opinions

C to Swift - Article 4


There have not been many subjects in computer programming that have intimidated me quite as much as Lambdas (C++) and Closures (Swift). Closures are very common in Swift APIs and it’s important to understand what they are, especially if you haven’t used Lambdas much in C++.

I want to start by saying this very important thing:Lambdas and Closures are just functions! The syntax is messy, confusing, and verbose in some cases, but they are just functions. When I started working with Swift I was very confused about a lot of APIs that used Closures and coming from C++, Lambdas were not something that were widely used. My exposure to them was minimal and the C++ syntax did not help.

The code snippet below is from a C++ assignment I was given in college that tasked us to write a lambda function that would be passed as an argument to the traverse method.

template<typename E>
typedef void (*FuncType)(const E& item) // Function Pointer
void BSTree<E>::traverse(FuncType func)
{
   // Do something with the function
}

This function was to print the item data and the syntax is very confusing for being such a simple function

auto fx = [ ] (const string& key) -> void { cout << key << endl; };

The function can then be used by an object like any other argument

BSTree<string> bsTree;

bsTree.traverse(fx);

The typedef declaration assigns FuncType to a function pointer that returns void and takes a const argument of type E& called item. That function pointer is then used across the data structure and is passed through in the traverse method of BSTree. In my solution, I use the auto keyword to assign a variable fx to the lambda function defined. Let’s dissect this function

In C++, using the auto keyword, you can easily assign a variable to a function and use that wherever needed.

The key parts of the lambda below are boxed in red.

C++ Lambda
Variable Type and NameThe name given to the function and you can define the type explicitly but using auto makes it easier
CapturesBecause Lambdas could be global functions, you may want to capture values such as local or global variables and do so by value or by reference
ArgumentsHere you would define any arguments to be used in your function definition like you would for any other function
Return TypeNote the Swift-like syntax with the arrow and return type
Function DefinitionDefine your function as you normally would using the arguments and captures


In Swift, assigning a Closure to a variable can be similar to C++ Lambdas

let fx: (String)->Void = { (key: String) -> Void in print(key) }
Swift Closure

Note in the image above we have the same fields with one obviously missing, Captures. This is because Swift automatically captures the calling functions variables by reference. You should take care when using Closures with other reference types such as the self keyword. Using self in a Swift closure will cause a retain cycle. How should you handle it then? By explicitly defining a closure capture list inside a pair of [ ] like so:

let fx: (String)->Void = { [weak prop = self.prop](key: String) -> Void in 
	print(key)
	// do something with prop in code
 }

This will allow Swift to capture self.prop and avoid a retain cycle which causes memory leaks. The syntax becomes similar to C++ Lambdas when you have a closure list with a Swift Closure.

Now that we have addressed what Lambdas and Closures are and the syntax of both C++ and Swift, let’s take a quick look at some of the applications of Closures in Swift. As I mentioned before, I have found that newer language features in C++ are not as common as some features in Swift such as Lambdas. Apple has many libraries and frameworks that take Closures in its APIs in the form of completion handlers. It is very common to see code written like so:

let numbers = [3,6,9,2,4,1]
var minNumber = 5
let lessThanMin = numbers.filter { $0 < minNumber }

This syntax is very confusing and not very friendly to new Swift programmers. The filter function is a function that expects a closure for you give it to apply to each element in the array that checks for a boolean, it then returns a new array with only the elements that satisfied that booleans true case.

The $0 is Swift closure syntax for the first argument of the closure. This was also a source of confusion as a new Swift developer. Let’s consider the sorted (by:) function of an array. The apple documentation shows this as the declaration

func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]

You can access the first Element with $0 and the second Element with $1 and we see here it returns an array [Element] The (param, param) throws -> Bool is what is telling us we will get an array with everything sorted in such a way that when you compare the two arguments, it returns true. When first using Closures, I recommend you be as verbose as possible to avoid unnecessary confusing syntax. A good example of using the sorted method on the same array above would be

let sortedNums = numbers.sorted (by: { (a: Int, b: Int) -> Bool in // we are explicitly saying a = $0 and b = $1
	if a < b {
		return true
	}
	return false
})

I say to be verbose because in my experience coming back to a function weeks or months later, or handing it off to be reviewed often delays review. This code is explicit and does not require any comments. The next two lines are the same function with much less code, but could confuse newcomers or even yourself down the road reviewing your own code. Note the lack of parentheses in the second example.

let sortedNums = numbers.sorted(by: <)
let sortedNums = numbers.sorted{ $0 < $1 }

The two methods above are clean and elegant but require a more advanced understanding of Swift type inference. Writing a longer more deliberate method helps me come back to that method and understand what it is doing quickly for my future self and newcomers.

That is it for my fourth article about programming in Swift for C/C++ developers. I hope this article has helped you get a little more comfortable with using Closures and Lambdas! If you have any comments or questions, or would like to inquire about freelance development help, please reach out via email or via Twitter

Thanks for reading!

With gratitude,
Jav Solo