8 years ago

Functional is about functions (Swift)

Since Swift 2.0 was launched this term has become very popular. You attend conferences and this is usually the topic most of the people talk about. You see people even struggling for its use in their apps, really overwhelming for it. Why? It’s something that can be easily done with Swift but it’s not something new (a lot of languages where already offering fully functional paradigms before)

Ey Pedro! Do you use functional in your apps? I wanna start using it, I’m watching a lot of talks and reading a couple of books. What do you think about? Should I use it?

Maths

Functions is not anything new, back in the school we were told that a function is something that has some input arguments or variables and after some operations they return a value. From the Engineer perspective I was told that these was systems or black boxes that depend on an input stream of data and the output only depends on the input in each instance (no feedback cycle systems)

f(x, y) = x + y

Notice that when we create a function we’re actually a scope of operations that doesn’t take data out of there, consequently the logic subset is constrained. Thinking about it the concept isn’t complex at all, but… we were given more flexibility when we were told that we could save states under something called classes, voila! OOP

Black box

Object oriented programming

We started grouping these functions into something called classes and assigning it a state which is created when and instance of this class is created. We still have functions but they seem to belong now to something and in languages like Objective-C we cannot extract them from its scope (ask a Javascript developer about functions and contexts and you’ll get surprise about what they’re able to do). We sticked to Object Oriented principles and we set ourselves far from the basic function concept we saw above. Object Oriented programming introduces a grade of flexibility and mutability working with objects and its functions. I’m sure most of you have coded something like this:

class ApiClient {

  // MARK: - Attributes

  var token: String?

  // MARK: - Init

  init(token: String) {
    self.token = token
  }

  // MARK: - Public

  func reset() {
    token = nil
    cancelRequests()
  }

  func execute(request: Request, completion: (Result<AnyObject, Error>) -> Void) {
    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
    	let authRequest: Request = self.authenticatedRequest(request)
    	// Execute the request and get the response: let result
    	dispatch_async(dispatch_get_main_queue()) {
    	  completion(result)
    	}
    }
  }

  // MARK: - Private

  func authenticatedRequest(request: Request) -> Request {
    // Authenticating
  }
}

Let’s analyse the problems the implementation above presents. It’s a typical pattern on mobile apps and I’ve seen lots of workarounds facing different unexpected states that weren’t taken into account when it was implemented (Note: This implementation can be more secure with Swift immutability concepts but I just copied how it would be using the same Objective-C format)

Note: Adding threading logic inside functions adds an extra complexity because by the time these closures are executed the state might have changed.

This is a common mistake for Objective-C, and most of them even don’t know what’s going on when they’re using reference objects inside blocks. Fortunately Swift solved it pretty well with types and retain level specification when closures are defined.

I’ve seem the problems above manifesting when the user logouts and you want to reset the state of your static/singleton API client. Things start to behave quite randomly.

Functional

Let’s bring our function concept and make it simpler. Remember:

func execute(request: Request, session: Session, completion: (Result<AnyObject, Error>) -> Void) {
  let authenticatedRequest: (Request, Session) -> (Request) = { request in
    // Authenticates the request
  }
  let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
  dispatch_async(dispatch_get_global_queue(priority, 0)) {
    let authRequest: Request = authenticatedRequest(request, session)
    // Execute the request and get the response: let result
    dispatch_async(dispatch_get_main_queue()) {
    	 completion(result)
    }
  }
}

The example above have in essence two functions:

g(request, session) = auth_request

f(request, session, completion) = execute(g(request, session), completion)

We’re not accessing any external scope that retains the state, we’re instead passing all the data needed for this operation as input parameters and even using internal helper functions that in the same way take input parameters and returns data.

As you see functional is not something magic, it’s something that has been always with us, but that being Objective-C developers we forgot and now we have the opportunity to use it again with a better and readable syntax.

Namespaces

Where should I place my functions?

With OOP it’s seems easier to organise our code logic, we have models, controllers, presenters, factories, … Each of these entities as its own file and we group them by type or by feature inside the app. But what about organising functions? Where should I have them? You can do it everything as top level entities but you’ll end up messing up the top-level namespace with tons of functions.

Building namespaces with Structs My suggestion about this is use structs to create namespaces in Swift grouping the functions that are related to the same business logic. For example if you have a set of functions related to network. Group them under Network as shown below:

struct Network {
  static func execute(request: Request, completion: (Result<AnyObject, Error>) -> Void)
  static func authenticate(username: String, password: String, completion Result<Session, Error> -> Void)
}

Recommendations

If you’re thinking about using functional approaches in your Swift code but you don’t know how, or what to do don’t worry, it’s not something you have to necessarily do to get your app working, but it’s something definitively will help your code to be more reusable, robust, and stable. From my experience try to keep the following points in mind:

And overall, don’t overwhelm with this concepts. You can also use Object Oriented Programming with Functional safety thanks to Swift immutability concept concepts.

References

If you are interested also in the Reactive paradigm you can subscribe here https://leanpub.com/functionalreactiveprogrammingswift to a book I’m writing about Functional Reactive Programming with Swift.

About Pedro Piñera

I created XcodeProj and Tuist, and co-founded Tuist Cloud. My work is trusted by companies like Adidas, American Express, and Etsy. I enjoy building delightful tools for developers and open-source communities.