Skip to Content

Introduction

For many SAP developers, the Swift programming language has been a remote affair. You probably haven’t wrote a program in Swift, or maybe you haven’t heard of Swift at all. Which is a pity, because I tend to think of Swift as a beautiful, elegant and modern language. And many developers are picking it up too it seems, because just 3 years after it’s debut in 2014, it has entered the top 10 of most popular programming languages. And now the SAP Cloud Platform SDK for iOS is available for all SAP developers, nothing stops you from trying out Swift as well, and broaden your programming arsenal.

Learning Swift

If you’re like me, and come from a Java and/or Javascript background, you will notice the Swift language and syntax feel surprisingly familiar. If you’re not like me, and you come from an ABAP background like 90% of all SAP developers, then I can imagine Swift is a bit harder to grok. In any case, there are wonderful resources available to learn the Swift programming language:

In this blog, I assume you already have a basic understanding of Swift, and I will focus on Functional Programming and why you should embrace it out too.

Why should I do Functional Programming?

As a developer, you have certainly experienced that when programs get more complex, they become much harder to understand, and a s a result are much harder to maintain. However, if a complex program is structured well, it becomes easier to understand ands easier to debug, which makes it easier to apply changes.

Functional programming attempts to achieve this by producing readable, reusable, testable, structured code without any side-effects (side-effects are a huge cause of bugs, more on that later). It is about describing what you want, not how you want it to happen. In the end, your code will look a lot more elegant an better to read. And, more importantly, each separate function can be unit-tested separately

Javascript developers are already familiar with functional programming, and in this blog, I will show how to do it in Swift.

Ok, let’s get started

First, open Xcode on your Mac, and start a new Playground. You should see the following:

On the left, you write code. On the right, you see the results. Playgrounds are a perfect way to test out code. And you can even test UI functionality or external libraries like the SAP Cloud Platform SDK for iOS by adding the correct import statements, so you’re not limited to ‘text-only’ output.

Ok. Earlier I mentioned side-effects as a huge source for bugs. To show what I meant, add the following line underneath the existing variable declaration:

str = "Hi, Swift developer"

While this is perfectly executed code, but if you think of it, how could a variable assigned a particular value first (“Hello, playground”) and then later be something else (“Hi, Swift developer”)? It is exactly this mutable state that causes many bugs. To make it immutable, change your code from:

var str = "Hello, playground"
str = "Hi, Swift developer"

to

let str = "Hello, playground"
str = "Hi, Swift developer"

What do you see in the Playground’s console? By making it a constant, it now gives a compile error. Since you can’t change the string constant, you have to remove that second line. The side-effects issue is now solved.

Remove everything except for the import statement, and add the following code:

enum Department {
    case Sales
    case Finance
    case HR
    case Logistics
    case IT
}

struct Employee {
    let name: String
    let department: Set<Department>
    let budgetSpent: Double
}

Nothing fancy here; an enum with departments, and an Employee struct with a name field, department field and spent budget field.

Add the following array of employees:

let employees = [
    Employee(name: "Luke Skywalker", department: .Finance, budgetSpent: 1000.0),
    Employee(name: "Leia Organa", department: .Finance, budgetSpent: 250.0),
    Employee(name: "Obi-Wan Kenobi", department: .Sales, budgetSpent: 0.0),
    Employee(name: "Han Solo", department: .Sales, budgetSpent: 570.0),
    Employee(name: "Chewbacca", department: .HR, budgetSpent: 300.0),
    Employee(name: "BB-8", department: .IT, budgetSpent: 2795.0),
    Employee(name: "Finn", department: .IT, budgetSpent: 20.0),
    Employee(name: "Rey", department: .IT, budgetSpent: 312.0)
]

With this array we’ll be doing some array stuff like looping, counting and filtering.

If you’re a ‘traditional’ developer, you’re probably thinking of for-loops, and in that loop, look for a specific value, or increment a counter when looping over the list when determining how many employees work in IT.

You would probably write something like this:

var counter = 0
for employee in employees {
    if employee.department == .IT {
        counter+=1
    }
}
print(counter)

It will also produce the correct output:

However, the counter variable can potentially be overwritten and changed by another piece of code, and you won’t end up with the correct results (side-effects again)

With functional programming, you won’t do all of that. You only work with functions. You either execute a function, or you return a function.

Now, to get a list of only IT staff, you could use the filter function and check whether the department equals IT.

You could write it down using shorthand notation:

let itStaff = employees.filter { $0.department == .IT }
print(itStaff)

but this is pretty hard to read. A bit better is the following:

let itStaff = employees.filter { employee in employee.department == .IT }
print(itStaff)

but what if we want the staff count? We could add that to the filter as well, but again it will make it hard to read. It’s way better to make it a function:

func by(department: Department) -> ((Employee) -> Bool) {
    func isMemberOfDepartment(employee: Employee) -> Bool {
        return employee.department == department
    }
    return isMemberOfDepartment
}

let itStaff = employees.filter(by(department: .IT))
print(itStaff)

With this code, we don’t even need to know the inner workings of the function ‘by’, because the line

let itStaff = employees.filter(by(department: .IT))

makes it perfectly clear we filter the employees by IT department. But, what if we want the sum of the budget spent for everyone in that department? To calculate that, we can use the map and reduce functions. First, we map to the age field, and then calculate the total sum.

Change your code to the following:

func by(department: Department) -> ((Employee) -> Bool) {
    func isMemberOfDepartment(employee: Employee) -> Bool {
        return employee.department == department
    }
    return isMemberOfDepartment
}
func onBudgetSpent(employee: Employee) -> Double {
    return employee.budgetSpent
}
func toSumBudgetSpent(prev: Double, count: Double) -> Double {
    return prev + count
}


let itStaffBudgetSpent = employees
    .filter(by(department: .IT))
    .map(onBudgetSpent)
    .reduce(0, toSumBudgetSpent)

print(itStaffBudgetSpent)

See how easy it is to read?

The functions are merely there to make things happen, and because these are separate functions, they can be unit tested separately as well. The real beauty is in this single line of code:

To get the staff spent by the IT staff, you filter by IT department, then get the field for spend budget, on which you calculate the total amount.

And we have the answer to our question: the budget spent by IT staff is 3127.0

And today, March 30 2017, the SAP Cloud Platform SDK for iOS is GA. If you are a Swift developer, check out the SDK and see how easy and straightforward it is to build native iOS applications which connect to that pesky SAP backend. And if you are an SAP developer with an interest in mobile applications, you’ll see how easy it is to master the Swift programming language. And I hope, with this short blog, your code will eventually read like a poem.

And don’t forget to let me know what you think about functional programming in the comments

To report this post you need to login first.

7 Comments

You must be Logged on to comment or reply to a post.

  1. Moya Watson

    This is awesome Robin – thanks for putting it together and sharing it.  Time to learn Swift indeed…

     

    PS: looking forward to the poetry

    (1) 
  2. Marshall Elfstrand

    Thanks for writing this up, Robin!

    Along the lines of beautiful code, one great new feature in Swift 3.1 (with Xcode 8.3) is the ability to add constrained extensions. For those new to Swift, extensions let you add functionality to a type — such as a class, struct, or enum — after the fact. For example, we could extend the Employee enum to be able to provide a budget summary:

        extension Employee {
            var budgetSummary: String {
                return "\(name) has spent \(budgetSpent)."
            }
        }

    That way, rather than having a global function like budgetSummary(for: employee), we can call employee.budgetSummary, which is a more natural syntax in Swift, and supports auto-complete in Xcode.

    Extensions can also be used on built-in types like Array, but suppose we want to add a method to Array that only applies to Arrays of Employees? That’s where constrained extensions come in:

        extension Array where Element == Employee {
    
            /// Returns the list of employees in a specific department.
            func inDepartment(_ department: Department) -> [Employee] {
                return self.filter { $0.department == department }
            }
    
            /// Returns the list of `budgetSpent` amounts for all employees.
            var budgetsSpent: [Decimal] {
                return self.map { $0.budgetSpent }
            }
    
        }

    This extends just arrays of Employees, and adds one method (to filter the array by department) and one computed property (to get the array of just the budgets spent by each employee). Note that the budget in this example is the Decimal type, which is the type to use for currency.

    We can then add a handy property for Arrays of Decimals as well:

        extension Array where Element == Decimal {
    
            /// Computes the sum of all amounts in the array.
            var sum: Decimal {
                return self.reduce(0) { sum, amount in sum + amount }
            }
    
        }

    With these two extensions, the line for retrieving the total budget spent becomes:

        let budgetSpent = employees.inDepartment(.IT).budgetsSpent.sum

    And we get the usual advantages of extensions: they are namespaced to just where they’re needed (instead of globally), they use the familiar dot syntax, and they get auto-completed in Xcode.

    Hope this is helpful. Enjoy!

     

    (3) 
    1. Robin van het Hof Post author

      Hi Marshall,

      This. Is. Truly. Fantastic!

      I haven’t looked into constrained extensions yet, but it appears I definitely should have — this makes your code look like a solid A+ whereas mine looks like a mere C-… 😳

      Many thanks for taking the time writing this thorough reply and educating myself as well as the SAP community! Much appreciated!

      Now if you’ll excuse me, I’m off getting my Swift skills up to par…

      (1) 

Leave a Reply