Functional Swift: Using Array filter and forEach functions

Recently, I started learning a couple of functional languages through online MOOCs:

Swift isn’t classified as a functional language. However, that doesn’t mean we can’t use lessons learned from functional programming to improve our code. In this article, I illustrate a few ways my programming has changed after a couple of weeks of functional programming.

[].filter

There are many places in my code that looked something like this snippet:

self.retestQuestions = []

for q in questionList {
    if !q.isAnsweredCorrectly {
        self.retestQuestions.append(q)
    }
}

This translates to one line of Swift code:

let retestQuestions = questionList.filter({!$0.isAnsweredCorrectly})

In the past, I’ve used filter() to replace NSPredicate statements, which I used extensively in Objective C. In my first conversion to Swift, I directly translated my Objective C to Swift then cast my Swift array back to an NSArray to get the filter to work. Roughly my code looked like this:

let predicate = NSPredicate(format: "numWordsInGroup >= \(minWordCount) and  numPicturesInGroup >= \(minPictureCount)")

let answer = (a1 as NSArray).filtered(using: predicate)

Embracing the Array filter() function makes a lot more sense:

let answer = a1.filter({$0.numWordsInGroup >= minWordCount && $0.numPicturesInGroup >= minPictureCount})

After only a couple of weeks of functional programming, I’ve noticed many places in my code where this example, and other

[].forEach

The forEach() function isn’t a functional concept. However, without going into detail, my functional programming has led me to prefer using the Array forEach function more often. Here are several snippets from my code:

Add subviews to parent

[pronounView, answerWellView, answerConjugationView].forEach {self.mainContainerView.addSubview($0)}

Update: Someone pointed out on Reddit that this can be simplified:

// Simply pass func to apply to each element
[pronounView, answerWellView, answerConjugationView].forEach (mainContainerView.addSubview)

Active constraints

[c1, c2].forEach {NSLayoutConstraint.activate($0)}

Applying the same concept of passing the function as an argument to forEach(), activating constraints is even simpler.

[c1, c2].forEach(NSLayoutConstraint.activate) 

translatesAutoresizingMaskIntoConstraints and addSubviews

[answer1Btn, answer2Btn, answer3Btn, answer4Btn].forEach {
    $0.translatesAutoresizingMaskIntoConstraints = false
    self.cardFrontSubView.addSubview($0)
}

Disable and hide buttons

[answer1Btn,answer1Btn,answer3Btn,answer4Btn].forEach {
    $0.isEnabled = false
    $0.isHidden = false
}

Conclusion

I’ve just finished the second week, of a six week, Haskell MOOC. Hopefully, soon I’ll be using more functional concepts and my code will be “cleaner”, and more importantly contain fewer bugs.

Advertisements

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