Declarative programming vs Imperative programming

Hello programmers, I’m trying to study the differences between imperative programming and declarative programming. I read a lot of forums and topics but the concept is not clear to me.

This is an example of imperative programming:

fun getImperativeUncleBob() : String {
    for (c in collection) {
        if (c.equals("uncle bob")) {
           return c
        }
    }
  return ""
}

Here, we are saying step by step what we want to do. Like, we are iterating a collection, and we are doing a condition to see if an element is equals to “uncle bob”.

This is an example of declarative programming:

fun getDeclarativeUncleBob() : String {
    return collection.stream().filter {
        it -> it.equals("uncle bob")
    }.findAny().get()
}

Here we are declarating that we want to filter, we don’t know and we don’t have to know how the code will handle the iteration/recursion to attend the “it.equals(“uncle bob”)” condition, we just know that they will filter, will find any and will get the String.

My doubts:

  • Are these examples, good examples to explain the difference between declarative programming and imperative programming?
  • In the case of collection.stream().filter { //condition }.findAny().get(), if in the implementation of the stream().filter().findAny() it does the logic in imperative style, even if I’m just using it, is my code still declarative?

I’m new here and I’m very excited that I can learn with you guys. :slight_smile:

1 Like

Your second example is functional programming using high function. HTML is a declarative language, they describe thing but you cannot perform calculation.

fun Collection.getDeclarativeUncleBob() = this
.stream()
.filter { it == "uncle bob" }
.findAny()
.get() 

fixed this

1 Like

Are these examples, good examples to explain the difference between declarative programming and imperative programming

Yes, your streaming API example is somewhat declarative. But it might be too simple to understand the difference between declarative and imperative.

A good declarative example can be given using the kotlinx-html library.

Imperative example:

fun printPage(h1Text: String?, items: List<String>) {
    print("<html>")
    print("<head></head>")
    print("<body>")
    if (h1Text != null) {
        print("<h1>" + h1Text + "</h1>")
    }

    print("<ul>")
    for (item in items) {
        print("<li>" item  "</li>")
    }
    print("</ul>")
    print("</body>")
    print("</html>")
}

Same example, but declarative with kotlinx-html:

fun printPage(h1Text: String?, items: List<String>)  = System.out.appendHtml {
    html {
        head { }
        body {
            h1Text?.let {
                h1 { +it }
            }

            ul {
                items.forEach {
                    li { +it }
                }
            }
        }
    }
}

Both examples are kotlin code, and print the same html to the standard out. In the first example, it is very obvious how this is achieved. In the second example, the “how” is hidden away. It focuses on the “what”. The “how” vs “what” is often the differences between imperative and declarative programming.

if in the implementation [of the library] the logic is imperative style, even if I’m just using it, is my code still declarative?

It does not matter what paradigm was used to implement the kotlinx-html API (imperative, declarative, functional, oop, or a mix). The example code above is declarative in any case. In the end, every declarative framework is implemented on machine code, which is highly imperative mostly.

2 Likes

I’m not a huge fan of the discussion of imperative vs declarative programming. The best explanation is the ‘what’ vs ‘how’, and it shows exactly how the difference is really a matter of context. When you think about it, every ‘what’ is another man’s ‘how’. It’s a matter of abstraction levels.

4 Likes

I would second jacobz_20’s sentiment. Declarative vs Imperative is very rarely black and white, but rather on a spectrum, a grayscale.

To repeat jacobz_20, the central crux is “what” vs “how”. But every example is relative.

The more the program reads like an expression of business logic than instructions for a computer, generally the more declarative.

Like I said, declarative or imperative is not black and white. Almost every declarative has imperative traces.

Here’s some examples of your function, going from (most imperative and least declarative) to (least imperative and most declarative)

fun getUncleBobVeryImperative() : String {

    // notice the meaningless variable names
    val c = ArrayList<String>()
    // notice the tedious operations just to get to the point
    c.add("aunt alice")
    c.add("uncle bob")
    c.add("joe plumber")

    // notice that loop index is just a control flow cog that we wouldn't care about if we didn't have to
    var i = 0
    // more crappy variable names
    val r = ArrayList<String>()
    // You have to tell the program how to do everything, like when to stop looping
    while (i < c.size) {
        val p = c[i]
        // i++ means nothing to the business logic, but we write it anyway
        i++
        // finally a part of the program we are actually interested in - is uncle bob here or not?
        if (p == "uncle bob") {
            // see how this is wide away from the return statement, when in fact it is the key moment we are looking for
            r.add(p)
            // tell the loop how to stop
            break
        }
    }

    // manually figure out if sought out data is there or not
    // pull out the user with cryptic [0], whatever that means. What does "[0]" have to do with my uncle bob?
    return if (r.size > 1) r[0] else ""
}

fun getUncleBobJavaFunctional() : String {

    // declare your collection all at once - no "add()" invocations
    // Still, what do "Arrays" have to do with anything?
    // much better more meaningful variable name
    val people = Arrays.asList("aunt alice", "uncle bob", "joe plumber")

    // what is a stream? why do I care what a stream is?
    return people.stream()
        // It's obvious we are filtering something... why specify the parameter? can't it be implicit?
        // I want to see if uncle bob is in the collection of people. What does that have to do with the word 'filter'?
        .filter { it -> it == "uncle bob" }
        // "findAny" sounds closer to what we are actually trying to do - find any Bob. (contrast with "filter")
        .findAny()
        // "orElse" is fairly declarative, like saying: find "uncle bob" or else ""
        // "Optional.get" would be less declarative, because it leaks the implementation tedium without lending extra
        //     meaning to the business logic
        .orElse("")
}

fun getUncleBobKotlinNaive() : String {

    // flawless declarative syntax for creating a list
    val people = listOf("aunt alice", "uncle bob", "joe plumber")

    // no stream, why do we care what a stream is? just filter. awesome.
    // filter is still not perfectly declarative
    //     it is a declarative way to filter out results in a collection
    //     it is an imperative way to see if uncle bob *exists* in a collection
    // implicit parameter "it" is awesome
    // "first" of "firstOrNull" is pretty declarative, but mentioning "null" at all leaks the fact we are still giving
    //     instructions to a computer
    
    return people.filter { it == "uncle bob" }.firstOrNull() ?: ""
}

fun getUncleBobKotlinIdiomatic() : String {

    // declare people
    val people = listOf("aunt alice", "uncle bob", "joe plumber")

    // key phrase "find" is more declarative than "filter", we want to find bob, not filter a collection
    // It is still imperative though, because we don't ACTUALLY want to find bob, we want to know if he is in the list
    // the ?: is highly imperative, leaking the 'semantics of implementation' with handling null explicitly
    return people.find { it == "uncle bob" } ?: ""
}

fun getUncleBobKotlinWiseAss() : String {

    // declare people
    val people = listOf("aunt alice", "uncle bob", "joe plumber")

    // declare bob
    val bob = "uncle bob"

    // if bob is in people, then return bob, otherwise return ""
    // it is VERY difficult to make something more declarative without actually making things more complicated
    // there's no while(), there's no stream(), no filter(), no find(), we just want to know if bob is in people
    // we ask if bob is in people, and that's what we get. Declarative rather than imperative.
    return if (bob in people) bob else ""
}
5 Likes

I didn’t know about this kotlinx-html. That’s pretty nice! It is an excellent example. Thank you very much. :slight_smile:

1 Like

I totally agree with you. Sometimes I feel some difficulties to understand these concepts. In practice, I try to ask to myself if I’m coding telling how it will be done or what is being done just to see the difference between them.
I don’t know if the imperative (how) is a bad practice. Great part of the systems today have imperative code and I believe it is hard to do a refactoring of it at all. And I know a lot of libraries have imperative code.

Excellent examples @abrownvt.

Almost every declarative has imperative traces

Every programmer must understand what you said above. I’m not a fanatic but I believe tightly in this sentence.
I read a lot of articles that says imperative programming is a bad practice. That’s not true in my vision. We are walking to something more hybrid.
You’ve clarified my side. Thanks.

And thank you for you examples. :slight_smile:

There is another level to the decision. Yes, declarative might be easier to read and refactor, but sometimes it is just more efficient to just write the code imperative and be done with it.
In a perfect world this would be not so, but the time it takes to write something is to be considered as well. If you need this program once for a small task, is it worth it to spend hours just so you can extend it later? I think there are many situations where the answer is, I don’t think I will ever need to extend this so I wont bother and if I ever have to I will just do it again.
That doesn’t mean the code shouldn’t be well written, but sometimes it’s just not worth it to write your own kotlin-html style library to create a file of 5 lines.

1 Like

Not necessarily. What is bad is code duplication. Imperative style can often and easily lead to duplicated code that is very cumbersome to refactor into common code without using non-imperative paradigms (functional, declarative or oop).

I agree with Burkhard that declarative coding can add costs at the beginning that need to be considered. Luckily Kotlin reduces the costs of writing non-imperative code very much :slight_smile:

Furthermore, often there will already be a declarative library ready to use. I don’t think that anyone would argue against using kotlinx-html instead of the imperative version.

You’re looking for a simple, universal answer where there is no simple, universal answer. There is no right and wrong. It usually comes down to which approach works best, and in particular efficiency versus flexibility.

Lets say you have a business with many offices all over the place. You need to get a big box of stuff over to another office that happens to be across the road. Lets say you have an AI that you instruct, declaratively, to get the box to that office. It promptly books a pickup with FedEx and ships the package for delivery across the road.

Clearly this is not the best solution, it’s slow and expensive. Alternatively you might have instructed your AI imperatively: get a staff member to walk this box across the road to the other office.

Which is better? Well in this single case clearly the second approach is better, but only for that office. For getting a box to any office, the AI has the right approach, since walking boxes long distances is not going to work.

In reality declarative and imperative approaches are used alternatively and mixed together in real life and programming.

2 Likes