One of the challenges in learning a new language, be it human or computer, is learning to think in the language. Learning Swift is no different.
I’ve been spending the past several months working on the first iOS (iPhone) app that I’ll be releasing through the Apple app store. I’m writing it entirely in Swift 3, the latest version of the language. Yesterday, I was looking over the code to see if there were any places where I’d been thinking in a non-Swift fashion. This moment of reflection was triggered by my viewing of a very recently released class in Swift from one of the major online education sites. I was disappointed that the instructor was using an idiom that I knew was easily simplified in Swift. My disappointment made me wonder if I had similar issues.
The following is actual code from my upcoming app. I had originally created it’s core in C as an extensible example for teaching that language. The setup is as follows:
- the map is an array of connections from each room
- the number of connections from each room is fixed
- we are explicitly tracking the number of a given type of hazard
We want a function that returns true if there is hazard in one of the connecting rooms. Here’s the original code:
var hazardNear = false if hazardCount > 0 { for nextRoom in 0 ..< numberOfConnections { if hazardRooms.contains(exits[room][nextRoom]) { hazardNear = true break } } } return hazardNear
Pretty conventional C-esque stuff. The first thing that jumped out at me was the reliance on knowing the number of connections. Swift arrays are true collections. Let’s treat them as such.
var hazardNear = false if hazardCount > 0 { for nextRoom in exits[room] { if hazardRooms.contains(nextRoom) { hazardNear = true break } } } return hazardNear
When viewed this way, it’s obvious that we’re just filtering the collection based on a condition. So, just do that.
var hazardNear = false if hazardCount > 0 { hazardNear = exits[room].filter{hazardRooms.contains($0)}.count != 0 } return hazardNear
We’re filtering the array of rooms for ones that contain the hazard and checking for a non-zero count. But this is still a bit clunky. Let’s examine what we’re really asking.
var hazardNear = false if hazardCount > 0 { hazardNear = !exits[room].filter{hazardRooms.contains($0)}.isEmpty } return hazardNear
It’s far more clear to simply ask if the filtered array is non-empty directly. What’s left is one final simplification.
return hazardCount > 0 && !exits[room].filter{hazardRooms.contains($0)}.isEmpty
One might ask whether having an explicit count is necessary as the hazard array has a count. True. Although the hazard array is built based on the number of hazards, so I still need it to be around.
Overall, I fairly pleased with the results of the exercise. In the end, the code is much clearer in intent.