Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Qualiture
Active Contributor

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

7 Comments
Labels in this area