Iterative v. Declarative Functions

It’s widely accepted that declarative programming is “good” or “better” than imperative programming, but what do the terms even mean? It’s not enough to have a vague idea that declarative programming is easy to reason about - that certainly wasn’t enough for me in trying to understand the difference between the two.

Imperative programming is explained as *how* something is done, whereas a declarative approach deals with *what* is going to be done.

Before we dig further into this, it’s important to realize that declarative approaches are basically an abstraction over an imperative implementation. Think about it - if you’re ordering a drop coffee at a cafe, you can tell the barista “I’d like a pour over coffee”. That’s a declarative approach. If declarative approaches could exist by themselves, the barista would be able to turn to a paper filter and say to it “make a coffee”. That’s not possible. The barista NEEDS to know *how* to make the coffee - that’s the imperative implementation underneath our declarative coffee order. The *what* must be backed by a *how* at some point down the line.

Enough with the fluff - let’s look at some a concrete example in code. In Swift - write an imperative function that accepts an array as a parameter and returns a new array containing all of the previous array elements minus 3.

func subtractThree (fromArray array:Array<Int>) -> Array<Int> {
    var returnArray: [Int] = []
    for item in array {
        returnArray.append(item-3)
    }
    return returnArray
}
  

The above code is difficult to understand at first sight compared to a more declarative approach. We can easily find the operation being performed on each array element because we’re we’ll versed with the general structure of a for loop. However, the code still tells us how we loop over the array instead of directly conveying what we want to achieve.

Loops can be rewritten declaratively by using higher order array functions (map, flatMap, etc). Written declaratively, the above would look like this:

func declarativeSubtractThree(fromArray array: Array<Int>) -> Array<Int> {
    let returnArray = array.map{$0-3}
    return returnArray
}

We’re expressing the logic of an operation without having to describe the control flow involved - this is declarative programming.