Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Going functional in Swift, but only a bit.

Going functional in Swift, but only a bit.

There's a lot of hype around functional programming these days and since Swift from day 0 supported a lot of functional concepts, we may have this gut feeling that it can be a functional language, but... It's not.
Swift is happily merried to the iOS/macOS ecosystem, which is obviously Object Oriented, so there's no escape!
Fortunately, we use those functional patterns everyday (sometimes we forget about them...) and I want to show you in this presentation how to spot them and how to use them and, even, how to take benefit of applying a bit of functional programming to our Swift world.

Mateusz Zając

March 23, 2017
Tweet

More Decks by Mateusz Zając

Other Decks in Programming

Transcript

  1. In Swift, you fundamentally work in a procedural/OOP paradigm, and

    the whole language is built around that — Rob Napier http://robnapier.net/swift-is-not-functional
  2. There are some tools available to let you jump over

    to a functional style when it’s useful — Rob Napier http://robnapier.net/swift-is-not-functional
  3. We need to be aware of functional patterns, and learn

    how to use them on daily basis to make our lives easier — Paulo Coelho Just kidding... It's me!
  4. !!!

  5. func viewDidLoad() -> Void { super.viewDidLoad() configureBasicStuff() -> Void prepareSomeFood()

    -> Void if production { configureSomeFancyProperties() -> Void } else { showMeSomeMemes() -> Void } }
  6. func configureBasicStuff() { doSomeMagic() networkingManager = SuperDuperNetworking.sharedInstance() for constraint in

    textConstraints { constraints.append(LayoutConstraint(constraint)) } label.text = "This is wrong!".uppercaseString label.font = UIFont(name: "CirceBold", size: 11) label.textColor = UIColor.blueColor() label.textAlignment = .Center label.numberOfLines = 1 label.constraints = constraints }
  7. func configureBasicStuff() { doSomeMagic() self.networkingManager = SuperDuperNetworking.sharedInstance() for constraint in

    textConstraints { self.constraints.append(LayoutConstraint(constraint)) } self.label.text = "This is wrong!".uppercaseString self.label.font = UIFont(name: "CirceBold", size: 11) self.label.textColor = UIColor.blueColor() self.label.textAlignment = .Center self.label.numberOfLines = 1 self.label.constraints = self.constraints }
  8. func configureBasicStuff() { doSomeMagic() networkingManager = SuperDuperNetworking.sharedInstance() for constraint in

    textConstraints { constraints.append(LayoutConstraint(constraint)) } label = configureLabel(constraints: constraints) }
  9. A BIT OF HIGHER ORDER FUNCTIONS? func configureBasicStuff() { doSomeMagic()

    // BUT WE STILL HAVE THIS MAGIC THING AROUND! networkingManager = SuperDuperNetworking.sharedInstance() let constraints = textConstraints.map { LayoutConstraint($0) } label = configureLabel(constraints: constraints) }
  10. func doSomeMagic() { // Some stuff is happening here }

    func doSomeMagic(ingredients: [MagicIngredient]) -> Magic? { // Some stuff is happening here as well, but we know the input // And we know the return type }
  11. LET'S WRITE SOME TEST CASES func testEmptyDoSomeMagic { let result

    = doSomeMagic([]) XCTAssertNil(result, "No ingredients, no magic!") } func testDoSomeMagic { let ingredients = [ .unicornHorn, .wizardsTooth ] let result = doSomeMagic(ingredients) XCTAssertNotNil(result) } Those assertions won't compile, but you get my point, right?
  12. -- This is how typeclass for Eq looks like in

    Haskell class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x == y) -- And for our doSomeMagic it may look like... class Magical a where doSomeMagic :: a -> [MagicIngredient] -> Maybe Magic
  13. AND USE IT LIKE... final class MagicalVC: ViewController, Magical {

    var magicProperty: Magic? = nil override func viewDidLoad() { super.viewDidLoad() magicProperty = doSomeMagic([]) } func doSomeMagic(ingredients: [MagicIngredient]) -> Magic? { // Some actual magic is happening here! ! } }
  14. The optionality of the property represents more than existence —

    Soroush Khanlou http://khanlou.com/2017/03/that-one-optional-property/
  15. It has implications in the rest of the view controller

    and the rest of the view layer — Soroush Khanlou http://khanlou.com/2017/03/that-one-optional-property/
  16. -- Here's Haskelly Either data Either a b = Left

    a | Right b // And here we have Swifty version enum Either<A, B> { case left(A) case right(B) }
  17. WE MAY END UP LIKE THIS enum Magic { case

    noMagic case darkMagic(String) case someHarryPotterStuff(String) }
  18. Pattern matching ❤ func alertMessage(for magic: Magic) -> String {

    switch magic { case .someHarryPotterStuff(let magicSpell): return "Harry Potter says \(magicSpell)" case .darkMagic: return "Some Avada Kedavra shit!" case .noMagic: return "Nothing to be afraid of..." } }
  19. TO REMEBER: > Side effects > Higher order functions >

    Pure functions > Typeclasses > Algebraic data types We've also covered functors and monads, but this is our secret! !