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. GOING FUNCTIONAL IN SWIFT, BUT ONLY A BIT CocoaHeads Krakow,

    2017
  2. I'M @COJOJ

  3. THERE'S NO AGENDA... THERE ARE SOME QUESTIONS, THOUGH... ❓

  4. IS SWIFT A FUNCTIONAL LANGUAGE?

  5. None
  6. IS SWIFT MULTI- PARADIGM?

  7. None
  8. IS SWIFT DESIGNED FOR OOP?

  9. None
  10. WTF, MATEUSZ?

  11. 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
  12. SOME EVIDENCES... > UIKit > NSObject > ViewController aka UIViewController

    > <T>
  13. 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
  14. 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!
  15. FUNCTIONAL SWEET SPOTS > Testing > Modularity > Maintenance/Extendability >

    Reliability > Code safety
  16. !!!

  17. I'LL GUIDE YOU!

  18. func viewDidLoad() { super.viewDidLoad() configureBasicStuff() prepareSomeFood() if production { configureSomeFancyProperties()

    } else { showMeSomeMemes() } }
  19. TYPICAL! HOW DO I TEST ALL OF THIS!?

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

    -> Void if production { configureSomeFancyProperties() -> Void } else { showMeSomeMemes() -> Void } }
  21. RETURNING Void BUT WHY?

  22. SIDE EFFECTS

  23. 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 }
  24. 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 }
  25. func configureBasicStuff() { doSomeMagic() networkingManager = SuperDuperNetworking.sharedInstance() for constraint in

    textConstraints { constraints.append(LayoutConstraint(constraint)) } label = configureLabel(constraints: constraints) }
  26. 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) }
  27. PURE FUNCTIONS

  28. 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 }
  29. 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?
  30. Anyway, we're still trapped inside ViewController ... And if we

    want to test we've to escape!
  31. TYPECLASSES

  32. READY FOR SOME HASKELL?

  33. -- 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
  34. PROTOCOL-ORIENTED PROGRAMMING

  35. WE CAN DEFINE A PROTOCOL... protocol Magical { func doSomeMagic(ingredients:

    [MagicIngredient]) -> Magic? } Your Ad Here !
  36. 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! ! } }
  37. NOW, MOCKING'S BECAME REALLY EASY, HASN'T IT? And Dependency Injection

    as well... !
  38. THIS OPTIONAL Magic? PROPERTY

  39. The optionality of the property represents more than existence —

    Soroush Khanlou http://khanlou.com/2017/03/that-one-optional-property/
  40. 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/
  41. ALGEBRAIC DATA TYPES

  42. -- 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) }
  43. WE MAY END UP LIKE THIS enum Magic { case

    noMagic case darkMagic(String) case someHarryPotterStuff(String) }
  44. 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..." } }
  45. THERE'S MUCH MORE!

  46. 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! !
  47. TRIBUTE!

  48. THANKS! ! QUESTIONS?